@umituz/react-native-ai-generation-content 1.26.33 → 1.26.35
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 +1 -1
- package/src/domain/entities/index.ts +0 -2
- package/src/index.ts +4 -10
- package/src/infrastructure/providers/generation-config.provider.tsx +4 -4
- package/src/infrastructure/providers/index.ts +1 -1
- package/src/infrastructure/services/generation-orchestrator.service.ts +8 -1
- package/src/domain/entities/middleware.types.ts +0 -56
- package/src/domain/entities/progress.types.ts +0 -27
- package/src/infrastructure/middleware/README.md +0 -378
- package/src/infrastructure/middleware/credit-check.middleware.ts +0 -74
- package/src/infrastructure/middleware/history-tracking.middleware.ts +0 -69
- package/src/infrastructure/middleware/index.ts +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.35",
|
|
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",
|
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
export * from "./error.types";
|
|
7
7
|
export * from "./generation.types";
|
|
8
8
|
export * from "./polling.types";
|
|
9
|
-
export * from "./progress.types";
|
|
10
|
-
export * from "./middleware.types";
|
|
11
9
|
export * from "./job.types";
|
|
12
10
|
export * from "./processing-modes.types";
|
|
13
11
|
export * from "./flow-config.types";
|
package/src/index.ts
CHANGED
|
@@ -18,13 +18,11 @@ export { AIErrorType } from "./domain/entities";
|
|
|
18
18
|
export type {
|
|
19
19
|
AIErrorInfo, AIErrorMessages, GenerationCapability, GenerationStatus, GenerationMetadata,
|
|
20
20
|
GenerationResult, GenerationProgress, GenerationRequest, PollingConfig, PollingState,
|
|
21
|
-
PollingOptions,
|
|
22
|
-
|
|
23
|
-
BackgroundJobStatus, BackgroundJob, AddJobInput, UpdateJobInput, JobExecutorConfig,
|
|
24
|
-
BackgroundQueueConfig, GenerationMode,
|
|
21
|
+
PollingOptions, BackgroundJobStatus, BackgroundJob, AddJobInput, UpdateJobInput,
|
|
22
|
+
JobExecutorConfig, BackgroundQueueConfig, GenerationMode,
|
|
25
23
|
} from "./domain/entities";
|
|
26
24
|
|
|
27
|
-
export { DEFAULT_POLLING_CONFIG,
|
|
25
|
+
export { DEFAULT_POLLING_CONFIG, DEFAULT_QUEUE_CONFIG } from "./domain/entities";
|
|
28
26
|
|
|
29
27
|
export type { ImageProcessingMode, ModeConfig, ModeCatalog } from "./domain/entities/processing-modes.types";
|
|
30
28
|
export { DEFAULT_PROCESSING_MODES, getModeConfig, getFreeModes, getPremiumModes, getPromptRequiredModes } from "./domain/constants/processing-modes.constants";
|
|
@@ -45,9 +43,6 @@ export type {
|
|
|
45
43
|
ExecuteVideoFeatureOptions, VideoFeatureResult, VideoFeatureRequest,
|
|
46
44
|
} from "./infrastructure/services";
|
|
47
45
|
|
|
48
|
-
export { createCreditCheckMiddleware, createHistoryTrackingMiddleware } from "./infrastructure/middleware";
|
|
49
|
-
export type { CreditCheckConfig, HistoryConfig, HistoryEntry } from "./infrastructure/middleware";
|
|
50
|
-
|
|
51
46
|
export {
|
|
52
47
|
classifyError, isTransientError, isPermanentError, isResultNotReady, calculatePollingInterval,
|
|
53
48
|
createPollingDelay, checkStatusForErrors, isJobComplete, isJobProcessing, isJobFailed,
|
|
@@ -142,12 +137,11 @@ export * from "./domains/face-detection";
|
|
|
142
137
|
export * from "./domains/scenarios";
|
|
143
138
|
export * from "./infrastructure/orchestration";
|
|
144
139
|
|
|
145
|
-
// Generation Config Provider (App Configuration)
|
|
146
140
|
export {
|
|
147
141
|
GenerationConfigProvider,
|
|
148
142
|
useGenerationConfig,
|
|
149
143
|
type GenerationModels,
|
|
150
|
-
type
|
|
144
|
+
type GenerationConfigValue,
|
|
151
145
|
type GenerationConfigProviderProps,
|
|
152
146
|
} from "./infrastructure/providers";
|
|
153
147
|
|
|
@@ -35,7 +35,7 @@ export interface GenerationModels {
|
|
|
35
35
|
readonly textToVoice?: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export interface
|
|
38
|
+
export interface GenerationConfigValue {
|
|
39
39
|
/** AI models configuration from app */
|
|
40
40
|
readonly models: GenerationModels;
|
|
41
41
|
/** Get model for specific feature type */
|
|
@@ -46,7 +46,7 @@ export interface GenerationConfigContextValue {
|
|
|
46
46
|
// Context
|
|
47
47
|
// ============================================================================
|
|
48
48
|
|
|
49
|
-
const GenerationConfigContext = createContext<
|
|
49
|
+
const GenerationConfigContext = createContext<GenerationConfigValue | null>(null);
|
|
50
50
|
|
|
51
51
|
// ============================================================================
|
|
52
52
|
// Provider
|
|
@@ -91,7 +91,7 @@ export const GenerationConfigProvider: React.FC<GenerationConfigProviderProps> =
|
|
|
91
91
|
return model;
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
const value:
|
|
94
|
+
const value: GenerationConfigValue = {
|
|
95
95
|
models,
|
|
96
96
|
getModel,
|
|
97
97
|
};
|
|
@@ -107,7 +107,7 @@ export const GenerationConfigProvider: React.FC<GenerationConfigProviderProps> =
|
|
|
107
107
|
// Hook
|
|
108
108
|
// ============================================================================
|
|
109
109
|
|
|
110
|
-
export const useGenerationConfig = ():
|
|
110
|
+
export const useGenerationConfig = (): GenerationConfigValue => {
|
|
111
111
|
const context = useContext(GenerationConfigContext);
|
|
112
112
|
|
|
113
113
|
if (!context) {
|
|
@@ -71,7 +71,14 @@ class GenerationOrchestratorService {
|
|
|
71
71
|
await this.onStatusUpdateCallback(submission.requestId, status.status);
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
onProgress: request.onProgress
|
|
74
|
+
onProgress: request.onProgress
|
|
75
|
+
? (progress: number) => {
|
|
76
|
+
request.onProgress!({
|
|
77
|
+
stage: progress === 100 ? "completed" : "generating",
|
|
78
|
+
progress,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
: undefined,
|
|
75
82
|
});
|
|
76
83
|
|
|
77
84
|
if (!pollResult.success) {
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Middleware Types
|
|
3
|
-
* Generic middleware pattern for generation workflow
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { GenerationRequest, GenerationResult } from "./generation.types";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Context passed to middleware hooks
|
|
10
|
-
*/
|
|
11
|
-
export interface MiddlewareContext {
|
|
12
|
-
request: GenerationRequest;
|
|
13
|
-
userId?: string;
|
|
14
|
-
metadata?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Result context passed to afterGenerate hook
|
|
19
|
-
*/
|
|
20
|
-
export interface MiddlewareResultContext<T> extends MiddlewareContext {
|
|
21
|
-
result: GenerationResult<T>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Middleware hook executed before generation
|
|
26
|
-
* Can throw error to prevent generation
|
|
27
|
-
*/
|
|
28
|
-
export type BeforeGenerateHook = (
|
|
29
|
-
context: MiddlewareContext,
|
|
30
|
-
) => Promise<void> | void;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Middleware hook executed after generation (success or failure)
|
|
34
|
-
* Cannot modify result, used for logging/tracking
|
|
35
|
-
*/
|
|
36
|
-
export type AfterGenerateHook<T = unknown> = (
|
|
37
|
-
context: MiddlewareResultContext<T>,
|
|
38
|
-
) => Promise<void> | void;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Complete middleware configuration
|
|
42
|
-
*/
|
|
43
|
-
export interface GenerationMiddleware {
|
|
44
|
-
/** Hook executed before generation starts */
|
|
45
|
-
beforeGenerate?: BeforeGenerateHook;
|
|
46
|
-
/** Hook executed after generation completes (success or failure) */
|
|
47
|
-
afterGenerate?: AfterGenerateHook;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Middleware chain configuration
|
|
52
|
-
*/
|
|
53
|
-
export interface MiddlewareChain {
|
|
54
|
-
/** Array of middleware to execute in order */
|
|
55
|
-
middleware: GenerationMiddleware[];
|
|
56
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress Types
|
|
3
|
-
* Progress tracking for generation stages
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { GenerationStatus } from "./generation.types";
|
|
7
|
-
|
|
8
|
-
export interface ProgressStageConfig {
|
|
9
|
-
status: GenerationStatus;
|
|
10
|
-
minProgress: number;
|
|
11
|
-
maxProgress: number;
|
|
12
|
-
weight: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const DEFAULT_PROGRESS_STAGES: ProgressStageConfig[] = [
|
|
16
|
-
{ status: "preparing", minProgress: 0, maxProgress: 5, weight: 1 },
|
|
17
|
-
{ status: "moderating", minProgress: 5, maxProgress: 15, weight: 1 },
|
|
18
|
-
{ status: "submitting", minProgress: 15, maxProgress: 25, weight: 1 },
|
|
19
|
-
{ status: "generating", minProgress: 25, maxProgress: 85, weight: 6 },
|
|
20
|
-
{ status: "finalizing", minProgress: 85, maxProgress: 95, weight: 1 },
|
|
21
|
-
{ status: "completed", minProgress: 95, maxProgress: 100, weight: 1 },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
export interface ProgressConfig {
|
|
25
|
-
stages: ProgressStageConfig[];
|
|
26
|
-
estimatedDurations?: Record<string, number>;
|
|
27
|
-
}
|
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
# Infrastructure Middleware
|
|
2
|
-
|
|
3
|
-
Request/response middleware for AI generation operations.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The middleware module provides a flexible middleware system for intercepting and modifying AI generation requests and responses. Common use cases include credit checks, history tracking, content moderation, and logging.
|
|
8
|
-
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
- Request interception and modification
|
|
12
|
-
- Response processing
|
|
13
|
-
- Async middleware support
|
|
14
|
-
- Error handling
|
|
15
|
-
- Chainable middleware
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
### Creating Middleware
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
import type { GenerationMiddleware } from '@umituz/react-native-ai-generation-content';
|
|
23
|
-
|
|
24
|
-
const loggingMiddleware: GenerationMiddleware = {
|
|
25
|
-
name: 'logging',
|
|
26
|
-
|
|
27
|
-
before: async (context) => {
|
|
28
|
-
console.log('[Before]', {
|
|
29
|
-
featureType: context.featureType,
|
|
30
|
-
inputData: context.inputData,
|
|
31
|
-
});
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
after: async (context) => {
|
|
35
|
-
console.log('[After]', {
|
|
36
|
-
featureType: context.featureType,
|
|
37
|
-
result: context.result,
|
|
38
|
-
});
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
onError: async (context) => {
|
|
42
|
-
console.error('[Error]', {
|
|
43
|
-
featureType: context.featureType,
|
|
44
|
-
error: context.error,
|
|
45
|
-
});
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Credit Check Middleware
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
import { createCreditCheckMiddleware } from '@umituz/react-native-ai-generation-content';
|
|
54
|
-
|
|
55
|
-
const creditMiddleware = createCreditCheckMiddleware({
|
|
56
|
-
creditCost: 1, // Cost per generation
|
|
57
|
-
paywallThreshold: 5, // Show paywall after 5 insufficient credit attempts
|
|
58
|
-
onInsufficientCredits: async (userId, cost) => {
|
|
59
|
-
Alert.alert(
|
|
60
|
-
'Insufficient Credits',
|
|
61
|
-
`You need ${cost} credits to generate. Upgrade now?`,
|
|
62
|
-
[
|
|
63
|
-
{ text: 'Cancel', style: 'cancel' },
|
|
64
|
-
{ text: 'Upgrade', onPress: () => navigateToUpgrade() },
|
|
65
|
-
]
|
|
66
|
-
);
|
|
67
|
-
},
|
|
68
|
-
onPaywallTrigger: async () => {
|
|
69
|
-
await navigateToPaywall();
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### History Tracking Middleware
|
|
75
|
-
|
|
76
|
-
```tsx
|
|
77
|
-
import { createHistoryTrackingMiddleware } from '@umituz/react-native-ai-generation-content';
|
|
78
|
-
|
|
79
|
-
const historyMiddleware = createHistoryTrackingMiddleware({
|
|
80
|
-
maxHistorySize: 100, // Keep last 100 generations
|
|
81
|
-
storage: AsyncStorage, // Storage implementation
|
|
82
|
-
onHistoryUpdate: async (history) => {
|
|
83
|
-
console.log('History updated:', history.length);
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Content Moderation Middleware
|
|
89
|
-
|
|
90
|
-
```tsx
|
|
91
|
-
import { ModerationWrapper } from '@umituz/react-native-ai-generation-content';
|
|
92
|
-
|
|
93
|
-
const moderationMiddleware = {
|
|
94
|
-
name: 'moderation',
|
|
95
|
-
|
|
96
|
-
before: async (context) => {
|
|
97
|
-
// Check prompt for inappropriate content
|
|
98
|
-
if (context.inputData.prompt) {
|
|
99
|
-
const moderationResult = await moderateText(context.inputData.prompt);
|
|
100
|
-
if (!moderationResult.isSafe) {
|
|
101
|
-
throw new Error('Content flagged as inappropriate');
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Custom Middleware
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
const customMiddleware: GenerationMiddleware = {
|
|
112
|
-
name: 'custom',
|
|
113
|
-
|
|
114
|
-
before: async (context) => {
|
|
115
|
-
// Modify request before processing
|
|
116
|
-
if (context.featureType === 'text-to-image') {
|
|
117
|
-
context.inputData.prompt = enhancePrompt(context.inputData.prompt);
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
after: async (context) => {
|
|
122
|
-
// Process response after generation
|
|
123
|
-
if (context.result.success) {
|
|
124
|
-
await cacheResult(context.result);
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
onError: async (context) => {
|
|
129
|
-
// Handle errors
|
|
130
|
-
await logError(context.error);
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Middleware Chain
|
|
136
|
-
|
|
137
|
-
### Creating a Chain
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
import { MiddlewareChain } from '@umituz/react-native-ai-generation-content';
|
|
141
|
-
|
|
142
|
-
const chain = new MiddlewareChain([
|
|
143
|
-
creditMiddleware,
|
|
144
|
-
historyMiddleware,
|
|
145
|
-
moderationMiddleware,
|
|
146
|
-
loggingMiddleware,
|
|
147
|
-
]);
|
|
148
|
-
|
|
149
|
-
await chain.execute({
|
|
150
|
-
featureType: 'text-to-image',
|
|
151
|
-
inputData: { prompt: 'A sunset' },
|
|
152
|
-
execute: async (input) => {
|
|
153
|
-
// Actual generation logic
|
|
154
|
-
return await generateImage(input);
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Execution Order
|
|
160
|
-
|
|
161
|
-
Middlewares execute in order:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
Request → [Middleware 1] → [Middleware 2] → [Middleware 3] → Generation
|
|
165
|
-
↓ before ↓ before ↓ before
|
|
166
|
-
|
|
167
|
-
Response ← [Middleware 1] ← [Middleware 2] ← [Middleware 3] ← Result
|
|
168
|
-
↓ after ↓ after ↓ after
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Error Handling
|
|
172
|
-
|
|
173
|
-
If a middleware throws an error:
|
|
174
|
-
|
|
175
|
-
```
|
|
176
|
-
Request → [Middleware 1] → [Middleware 2] ✗ Error
|
|
177
|
-
↓ before ↓ onError
|
|
178
|
-
|
|
179
|
-
Response ← [Middleware 1] ← Error Propagated
|
|
180
|
-
↓ onError
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
## Context Types
|
|
184
|
-
|
|
185
|
-
### MiddlewareContext (Before)
|
|
186
|
-
|
|
187
|
-
```tsx
|
|
188
|
-
interface MiddlewareContext {
|
|
189
|
-
featureType: string;
|
|
190
|
-
inputData: any;
|
|
191
|
-
userId?: string;
|
|
192
|
-
options?: Record<string, any>;
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### MiddlewareResultContext (After)
|
|
197
|
-
|
|
198
|
-
```tsx
|
|
199
|
-
interface MiddlewareResultContext extends MiddlewareContext {
|
|
200
|
-
result: GenerationResult;
|
|
201
|
-
duration: number; // Time taken in ms
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### MiddlewareErrorContext (Error)
|
|
206
|
-
|
|
207
|
-
```tsx
|
|
208
|
-
interface MiddlewareErrorContext extends MiddlewareContext {
|
|
209
|
-
error: Error;
|
|
210
|
-
errorType: AIErrorType;
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
## Advanced Usage
|
|
215
|
-
|
|
216
|
-
### Conditional Middleware
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
const conditionalMiddleware: GenerationMiddleware = {
|
|
220
|
-
name: 'conditional',
|
|
221
|
-
|
|
222
|
-
before: async (context) => {
|
|
223
|
-
// Only apply to specific features
|
|
224
|
-
if (context.featureType === 'text-to-image') {
|
|
225
|
-
// Do something
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
|
-
};
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Async Middleware
|
|
232
|
-
|
|
233
|
-
```tsx
|
|
234
|
-
const asyncMiddleware: GenerationMiddleware = {
|
|
235
|
-
name: 'async',
|
|
236
|
-
|
|
237
|
-
before: async (context) => {
|
|
238
|
-
// Fetch data from API
|
|
239
|
-
const userData = await fetchUserData(context.userId);
|
|
240
|
-
context.inputData.userData = userData;
|
|
241
|
-
},
|
|
242
|
-
};
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### Modifying Input
|
|
246
|
-
|
|
247
|
-
```tsx
|
|
248
|
-
const inputModifier: GenerationMiddleware = {
|
|
249
|
-
name: 'input-modifier',
|
|
250
|
-
|
|
251
|
-
before: async (context) => {
|
|
252
|
-
// Add default options
|
|
253
|
-
if (!context.inputData.options) {
|
|
254
|
-
context.inputData.options = {};
|
|
255
|
-
}
|
|
256
|
-
context.inputData.options.quality = 'high';
|
|
257
|
-
},
|
|
258
|
-
};
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Processing Result
|
|
262
|
-
|
|
263
|
-
```tsx
|
|
264
|
-
const resultProcessor: GenerationMiddleware = {
|
|
265
|
-
name: 'result-processor',
|
|
266
|
-
|
|
267
|
-
after: async (context) => {
|
|
268
|
-
// Add metadata to result
|
|
269
|
-
context.result.metadata = {
|
|
270
|
-
...context.result.metadata,
|
|
271
|
-
processedAt: new Date().toISOString(),
|
|
272
|
-
};
|
|
273
|
-
},
|
|
274
|
-
};
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Best Practices
|
|
278
|
-
|
|
279
|
-
1. **Order Matters**: Put credit checks before generation
|
|
280
|
-
2. **Error Handling**: Always handle errors gracefully
|
|
281
|
-
3. **Performance**: Keep middleware lightweight
|
|
282
|
-
4. **Async Safety**: Handle async operations properly
|
|
283
|
-
5. **Side Effects**: Be careful with state mutations
|
|
284
|
-
|
|
285
|
-
## Example: Complete Setup
|
|
286
|
-
|
|
287
|
-
```tsx
|
|
288
|
-
import {
|
|
289
|
-
createCreditCheckMiddleware,
|
|
290
|
-
createHistoryTrackingMiddleware,
|
|
291
|
-
MiddlewareChain,
|
|
292
|
-
} from '@umituz/react-native-ai-generation-content';
|
|
293
|
-
|
|
294
|
-
// Create middlewares
|
|
295
|
-
const creditMiddleware = createCreditCheckMiddleware({
|
|
296
|
-
creditCost: 1,
|
|
297
|
-
onInsufficientCredits: async (userId) => {
|
|
298
|
-
Alert.alert('Low Credits', 'Please upgrade');
|
|
299
|
-
},
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const historyMiddleware = createHistoryTrackingMiddleware({
|
|
303
|
-
maxHistorySize: 100,
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
const analyticsMiddleware: GenerationMiddleware = {
|
|
307
|
-
name: 'analytics',
|
|
308
|
-
|
|
309
|
-
before: async (context) => {
|
|
310
|
-
await Analytics.track('generation_started', {
|
|
311
|
-
feature: context.featureType,
|
|
312
|
-
});
|
|
313
|
-
},
|
|
314
|
-
|
|
315
|
-
after: async (context) => {
|
|
316
|
-
await Analytics.track('generation_completed', {
|
|
317
|
-
feature: context.featureType,
|
|
318
|
-
success: context.result.success,
|
|
319
|
-
});
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// Create chain
|
|
324
|
-
const middlewareChain = new MiddlewareChain([
|
|
325
|
-
creditMiddleware,
|
|
326
|
-
historyMiddleware,
|
|
327
|
-
analyticsMiddleware,
|
|
328
|
-
]);
|
|
329
|
-
|
|
330
|
-
// Use chain
|
|
331
|
-
const result = await middlewareChain.execute({
|
|
332
|
-
featureType: 'text-to-image',
|
|
333
|
-
inputData: { prompt: 'A sunset' },
|
|
334
|
-
execute: async (input) => {
|
|
335
|
-
return await generateImage(input);
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## Testing
|
|
341
|
-
|
|
342
|
-
```tsx
|
|
343
|
-
import { MiddlewareChain } from '@umituz/react-native-ai-generation-content';
|
|
344
|
-
|
|
345
|
-
test('middleware executes in order', async () => {
|
|
346
|
-
const executionOrder: string[] = [];
|
|
347
|
-
|
|
348
|
-
const middleware1: GenerationMiddleware = {
|
|
349
|
-
name: 'middleware1',
|
|
350
|
-
before: async () => {
|
|
351
|
-
executionOrder.push('m1-before');
|
|
352
|
-
},
|
|
353
|
-
after: async () => {
|
|
354
|
-
executionOrder.push('m1-after');
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
const chain = new MiddlewareChain([middleware1]);
|
|
359
|
-
|
|
360
|
-
await chain.execute({
|
|
361
|
-
featureType: 'test',
|
|
362
|
-
inputData: {},
|
|
363
|
-
execute: async () => ({ success: true }),
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
expect(executionOrder).toEqual(['m1-before', 'm1-after']);
|
|
367
|
-
});
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
## Related
|
|
371
|
-
|
|
372
|
-
- [Config](../config/) - Service configuration
|
|
373
|
-
- [Services](../services/) - AI generation services
|
|
374
|
-
- [Orchestration](../orchestration/) - Generation orchestration
|
|
375
|
-
|
|
376
|
-
## License
|
|
377
|
-
|
|
378
|
-
MIT
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Credit Check Middleware Factory
|
|
3
|
-
* Generic credit checking with app-provided config
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { GenerationMiddleware } from "../../domain/entities";
|
|
7
|
-
|
|
8
|
-
export interface CreditCheckConfig {
|
|
9
|
-
/**
|
|
10
|
-
* Get credit type from operation type
|
|
11
|
-
* App-specific logic
|
|
12
|
-
*/
|
|
13
|
-
getCreditType: (operationType: string) => string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Check if user has available credits
|
|
17
|
-
* App provides implementation
|
|
18
|
-
*/
|
|
19
|
-
checkCredits: (
|
|
20
|
-
userId: string | undefined,
|
|
21
|
-
operationType: string,
|
|
22
|
-
) => Promise<{
|
|
23
|
-
success: boolean;
|
|
24
|
-
error?: string;
|
|
25
|
-
creditType?: string;
|
|
26
|
-
}>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Deduct credits after successful generation
|
|
30
|
-
* App provides implementation
|
|
31
|
-
*/
|
|
32
|
-
deductCredits: (
|
|
33
|
-
userId: string | undefined,
|
|
34
|
-
creditType: string,
|
|
35
|
-
) => Promise<void>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Create credit check middleware
|
|
40
|
-
* Checks credits before generation, deducts after success
|
|
41
|
-
*/
|
|
42
|
-
export function createCreditCheckMiddleware(
|
|
43
|
-
config: CreditCheckConfig,
|
|
44
|
-
): GenerationMiddleware {
|
|
45
|
-
return {
|
|
46
|
-
async beforeGenerate(context) {
|
|
47
|
-
const operationType =
|
|
48
|
-
(context.request.input?.type as string) || "default";
|
|
49
|
-
|
|
50
|
-
const result = await config.checkCredits(
|
|
51
|
-
context.userId,
|
|
52
|
-
operationType,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
if (!result.success) {
|
|
56
|
-
throw new Error(result.error || "credits_exhausted");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
context.metadata = {
|
|
60
|
-
...context.metadata,
|
|
61
|
-
creditType: result.creditType || config.getCreditType(operationType),
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
async afterGenerate(context) {
|
|
66
|
-
if (context.result.success && context.metadata?.creditType) {
|
|
67
|
-
await config.deductCredits(
|
|
68
|
-
context.userId,
|
|
69
|
-
context.metadata.creditType as string,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* History Tracking Middleware Factory
|
|
3
|
-
* Generic history saving with app-provided config
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { GenerationMiddleware } from "../../domain/entities";
|
|
7
|
-
|
|
8
|
-
export interface HistoryEntry {
|
|
9
|
-
type: string;
|
|
10
|
-
prompt: string;
|
|
11
|
-
result: string | null;
|
|
12
|
-
success: boolean;
|
|
13
|
-
error?: string;
|
|
14
|
-
userId: string;
|
|
15
|
-
metadata?: Record<string, unknown>;
|
|
16
|
-
timestamp: unknown;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface HistoryConfig {
|
|
20
|
-
/**
|
|
21
|
-
* Save generation to history
|
|
22
|
-
* App provides storage implementation (Firestore, API, etc.)
|
|
23
|
-
*/
|
|
24
|
-
saveToHistory: (entry: HistoryEntry) => Promise<void>;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Create timestamp for history entry
|
|
28
|
-
* App-specific (serverTimestamp for Firestore, new Date() for API, etc.)
|
|
29
|
-
*/
|
|
30
|
-
createTimestamp: () => unknown;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Create history tracking middleware
|
|
35
|
-
* Saves generation history after completion
|
|
36
|
-
*/
|
|
37
|
-
export function createHistoryTrackingMiddleware(
|
|
38
|
-
config: HistoryConfig,
|
|
39
|
-
): GenerationMiddleware {
|
|
40
|
-
return {
|
|
41
|
-
async afterGenerate(context) {
|
|
42
|
-
if (!context.userId) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const operationType =
|
|
48
|
-
(context.request.input?.type as string) || "default";
|
|
49
|
-
const prompt =
|
|
50
|
-
(context.request.input?.prompt as string) || "";
|
|
51
|
-
|
|
52
|
-
const entry: HistoryEntry = {
|
|
53
|
-
type: operationType,
|
|
54
|
-
prompt,
|
|
55
|
-
result: context.result.success ? String(context.result.data) : null,
|
|
56
|
-
success: context.result.success,
|
|
57
|
-
error: context.result.error,
|
|
58
|
-
userId: context.userId,
|
|
59
|
-
metadata: context.result.metadata as Record<string, unknown>,
|
|
60
|
-
timestamp: config.createTimestamp(),
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
await config.saveToHistory(entry);
|
|
64
|
-
} catch {
|
|
65
|
-
// Silent fail
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Middleware Factories
|
|
3
|
-
* Generic middleware with app-provided config
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
createCreditCheckMiddleware,
|
|
8
|
-
type CreditCheckConfig,
|
|
9
|
-
} from "./credit-check.middleware";
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
createHistoryTrackingMiddleware,
|
|
13
|
-
type HistoryConfig,
|
|
14
|
-
type HistoryEntry,
|
|
15
|
-
} from "./history-tracking.middleware";
|