@umituz/react-native-ai-creations 1.0.0 → 1.0.2
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 +3 -1
- package/src/domain/value-objects/CreationsConfig.ts +21 -0
- package/src/domain/value-objects/index.ts +2 -0
- package/src/index.ts +14 -1
- package/src/infrastructure/adapters/createRepository.ts +43 -4
- package/src/infrastructure/repositories/CreationsRepository.ts +71 -24
- package/src/infrastructure/repositories/index.ts +4 -1
- package/src/types.d.ts +35 -0
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-creations",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "AI-generated creations gallery with filtering, sharing, and management for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"typecheck": "tsc --noEmit",
|
|
9
9
|
"lint": "tsc --noEmit",
|
|
10
|
+
"version:patch": "npm version patch -m 'chore: release v%s'",
|
|
10
11
|
"version:minor": "npm version minor -m 'chore: release v%s'",
|
|
11
12
|
"version:major": "npm version major -m 'chore: release v%s'"
|
|
12
13
|
},
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"peerDependencies": {
|
|
30
31
|
"@tanstack/react-query": ">=5.0.0",
|
|
31
32
|
"@umituz/react-native-design-system": "latest",
|
|
33
|
+
"@umituz/react-native-firestore": "latest",
|
|
32
34
|
"@umituz/react-native-sharing": "latest",
|
|
33
35
|
"firebase": ">=11.0.0",
|
|
34
36
|
"react": ">=18.2.0",
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Defines the configuration for creations feature
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { Creation, CreationDocument } from "../entities/Creation";
|
|
7
|
+
|
|
6
8
|
export interface CreationType {
|
|
7
9
|
readonly id: string;
|
|
8
10
|
readonly labelKey: string;
|
|
@@ -20,12 +22,31 @@ export interface CreationsTranslations {
|
|
|
20
22
|
readonly filterAll: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Path builder function type
|
|
27
|
+
* Allows apps to define custom Firestore path structures
|
|
28
|
+
* @example
|
|
29
|
+
* // Default: users/{userId}/creations
|
|
30
|
+
* pathBuilder: (userId) => ["users", userId, "creations"]
|
|
31
|
+
* // Alternative: creations/{userId}/items
|
|
32
|
+
* pathBuilder: (userId) => ["creations", userId, "items"]
|
|
33
|
+
*/
|
|
34
|
+
export type PathBuilder = (userId: string) => string[];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Document mapper function type
|
|
38
|
+
* Allows apps to map their specific document structure to Creation
|
|
39
|
+
*/
|
|
40
|
+
export type DocumentMapper = (id: string, data: CreationDocument) => Creation;
|
|
41
|
+
|
|
23
42
|
export interface CreationsConfig {
|
|
24
43
|
readonly collectionName: string;
|
|
25
44
|
readonly types: readonly CreationType[];
|
|
26
45
|
readonly translations: CreationsTranslations;
|
|
27
46
|
readonly maxThumbnails?: number;
|
|
28
47
|
readonly gridColumns?: number;
|
|
48
|
+
readonly pathBuilder?: PathBuilder;
|
|
49
|
+
readonly documentMapper?: DocumentMapper;
|
|
29
50
|
}
|
|
30
51
|
|
|
31
52
|
export const DEFAULT_TRANSLATIONS: CreationsTranslations = {
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* AI-generated creations gallery with filtering, sharing, and management
|
|
5
5
|
*
|
|
6
|
+
* Architecture:
|
|
7
|
+
* - Extends BaseRepository from @umituz/react-native-firestore
|
|
8
|
+
* - Fully dynamic path structure (configurable per app)
|
|
9
|
+
* - Fully dynamic document mapping (configurable per app)
|
|
10
|
+
* - App-agnostic: Works with any app, no app-specific code
|
|
11
|
+
*
|
|
12
|
+
* This package is designed to be used across hundreds of apps.
|
|
13
|
+
*
|
|
6
14
|
* Usage:
|
|
7
15
|
* import {
|
|
8
16
|
* CreationsGalleryScreen,
|
|
@@ -27,6 +35,8 @@ export type {
|
|
|
27
35
|
CreationType,
|
|
28
36
|
CreationsTranslations,
|
|
29
37
|
CreationsConfig,
|
|
38
|
+
PathBuilder,
|
|
39
|
+
DocumentMapper,
|
|
30
40
|
} from "./domain/value-objects";
|
|
31
41
|
export { DEFAULT_TRANSLATIONS, DEFAULT_CONFIG } from "./domain/value-objects";
|
|
32
42
|
|
|
@@ -40,7 +50,10 @@ export type { ICreationsRepository } from "./domain/repositories";
|
|
|
40
50
|
// INFRASTRUCTURE LAYER
|
|
41
51
|
// =============================================================================
|
|
42
52
|
|
|
43
|
-
export {
|
|
53
|
+
export {
|
|
54
|
+
CreationsRepository,
|
|
55
|
+
type RepositoryOptions,
|
|
56
|
+
} from "./infrastructure/repositories";
|
|
44
57
|
export { createCreationsRepository } from "./infrastructure/adapters";
|
|
45
58
|
|
|
46
59
|
// =============================================================================
|
|
@@ -1,15 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Repository Factory
|
|
3
3
|
* Creates repository instance with given configuration
|
|
4
|
+
*
|
|
5
|
+
* Architecture:
|
|
6
|
+
* - Factory pattern for repository creation
|
|
7
|
+
* - Supports dynamic path structure per app
|
|
8
|
+
* - Supports custom document mapping per app
|
|
9
|
+
* - App-agnostic: No Firestore instance needed (BaseRepository handles it)
|
|
10
|
+
*
|
|
11
|
+
* This factory is designed to be used across hundreds of apps.
|
|
4
12
|
*/
|
|
5
13
|
|
|
6
|
-
import
|
|
7
|
-
|
|
14
|
+
import {
|
|
15
|
+
CreationsRepository,
|
|
16
|
+
type RepositoryOptions,
|
|
17
|
+
} from "../repositories/CreationsRepository";
|
|
8
18
|
import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
|
|
9
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new CreationsRepository instance
|
|
22
|
+
*
|
|
23
|
+
* @param collectionName - Firestore collection name
|
|
24
|
+
* @param options - Optional repository configuration
|
|
25
|
+
* @returns ICreationsRepository instance
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Basic usage with default path (users/{userId}/photos)
|
|
29
|
+
* const repo = createCreationsRepository("photos");
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Custom path structure
|
|
33
|
+
* const repo = createCreationsRepository("creations", {
|
|
34
|
+
* pathBuilder: (userId) => ["gallery", userId, "items"],
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Custom document mapper
|
|
39
|
+
* const repo = createCreationsRepository("photos", {
|
|
40
|
+
* documentMapper: (id, data) => ({
|
|
41
|
+
* id,
|
|
42
|
+
* uri: data.imageUrl,
|
|
43
|
+
* type: data.category,
|
|
44
|
+
* createdAt: data.timestamp?.toDate() || new Date(),
|
|
45
|
+
* isShared: data.public ?? false,
|
|
46
|
+
* }),
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
10
49
|
export function createCreationsRepository(
|
|
11
|
-
db: Firestore | null,
|
|
12
50
|
collectionName: string,
|
|
51
|
+
options?: RepositoryOptions,
|
|
13
52
|
): ICreationsRepository {
|
|
14
|
-
return new CreationsRepository(
|
|
53
|
+
return new CreationsRepository(collectionName, options);
|
|
15
54
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creations Repository Implementation
|
|
3
|
-
*
|
|
3
|
+
* Extends BaseRepository from @umituz/react-native-firestore
|
|
4
|
+
*
|
|
5
|
+
* Architecture:
|
|
6
|
+
* - Extends BaseRepository for centralized database access
|
|
7
|
+
* - Fully dynamic path structure (configurable per app)
|
|
8
|
+
* - Fully dynamic document mapping (configurable per app)
|
|
9
|
+
* - App-agnostic: Works with any app, no app-specific code
|
|
10
|
+
*
|
|
11
|
+
* This class is designed to be used across hundreds of apps.
|
|
4
12
|
*/
|
|
5
13
|
|
|
6
14
|
declare const __DEV__: boolean;
|
|
@@ -13,21 +21,72 @@ import {
|
|
|
13
21
|
updateDoc,
|
|
14
22
|
query,
|
|
15
23
|
orderBy,
|
|
16
|
-
type Firestore,
|
|
17
24
|
} from "firebase/firestore";
|
|
25
|
+
import { BaseRepository } from "@umituz/react-native-firestore";
|
|
18
26
|
import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
|
|
19
27
|
import type { Creation, CreationDocument } from "../../domain/entities/Creation";
|
|
20
28
|
import { mapDocumentToCreation } from "../../domain/entities/Creation";
|
|
29
|
+
import type {
|
|
30
|
+
PathBuilder,
|
|
31
|
+
DocumentMapper,
|
|
32
|
+
} from "../../domain/value-objects/CreationsConfig";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Repository options for dynamic configuration
|
|
36
|
+
* Apps can customize path structure and document mapping
|
|
37
|
+
*/
|
|
38
|
+
export interface RepositoryOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Custom path builder function
|
|
41
|
+
* @example (userId) => ["users", userId, "photos"]
|
|
42
|
+
* @example (userId) => ["creations", userId, "items"]
|
|
43
|
+
*/
|
|
44
|
+
readonly pathBuilder?: PathBuilder;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Custom document mapper function
|
|
48
|
+
* Maps Firestore documents to Creation entity
|
|
49
|
+
*/
|
|
50
|
+
readonly documentMapper?: DocumentMapper;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Default path builder: users/{userId}/{collectionName}
|
|
55
|
+
*/
|
|
56
|
+
const createDefaultPathBuilder =
|
|
57
|
+
(collectionName: string): PathBuilder =>
|
|
58
|
+
(userId: string) =>
|
|
59
|
+
["users", userId, collectionName];
|
|
60
|
+
|
|
61
|
+
export class CreationsRepository
|
|
62
|
+
extends BaseRepository
|
|
63
|
+
implements ICreationsRepository
|
|
64
|
+
{
|
|
65
|
+
private readonly pathBuilder: PathBuilder;
|
|
66
|
+
private readonly documentMapper: DocumentMapper;
|
|
21
67
|
|
|
22
|
-
export class CreationsRepository implements ICreationsRepository {
|
|
23
68
|
constructor(
|
|
24
|
-
private readonly db: Firestore | null,
|
|
25
69
|
private readonly collectionName: string,
|
|
26
|
-
|
|
70
|
+
options?: RepositoryOptions,
|
|
71
|
+
) {
|
|
72
|
+
super();
|
|
73
|
+
this.pathBuilder =
|
|
74
|
+
options?.pathBuilder ?? createDefaultPathBuilder(collectionName);
|
|
75
|
+
this.documentMapper = options?.documentMapper ?? mapDocumentToCreation;
|
|
76
|
+
}
|
|
27
77
|
|
|
28
78
|
private getUserCollection(userId: string) {
|
|
29
|
-
|
|
30
|
-
|
|
79
|
+
const db = this.getDb();
|
|
80
|
+
if (!db) return null;
|
|
81
|
+
const pathSegments = this.pathBuilder(userId);
|
|
82
|
+
return collection(db, pathSegments[0], ...pathSegments.slice(1));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private getDocRef(userId: string, creationId: string) {
|
|
86
|
+
const db = this.getDb();
|
|
87
|
+
if (!db) return null;
|
|
88
|
+
const pathSegments = this.pathBuilder(userId);
|
|
89
|
+
return doc(db, pathSegments[0], ...pathSegments.slice(1), creationId);
|
|
31
90
|
}
|
|
32
91
|
|
|
33
92
|
async getAll(userId: string): Promise<Creation[]> {
|
|
@@ -48,7 +107,7 @@ export class CreationsRepository implements ICreationsRepository {
|
|
|
48
107
|
|
|
49
108
|
return snapshot.docs.map((docSnap) => {
|
|
50
109
|
const data = docSnap.data() as CreationDocument;
|
|
51
|
-
return
|
|
110
|
+
return this.documentMapper(docSnap.id, data);
|
|
52
111
|
});
|
|
53
112
|
} catch (error) {
|
|
54
113
|
if (__DEV__) {
|
|
@@ -59,16 +118,10 @@ export class CreationsRepository implements ICreationsRepository {
|
|
|
59
118
|
}
|
|
60
119
|
|
|
61
120
|
async delete(userId: string, creationId: string): Promise<boolean> {
|
|
62
|
-
|
|
121
|
+
const docRef = this.getDocRef(userId, creationId);
|
|
122
|
+
if (!docRef) return false;
|
|
63
123
|
|
|
64
124
|
try {
|
|
65
|
-
const docRef = doc(
|
|
66
|
-
this.db,
|
|
67
|
-
"users",
|
|
68
|
-
userId,
|
|
69
|
-
this.collectionName,
|
|
70
|
-
creationId,
|
|
71
|
-
);
|
|
72
125
|
await deleteDoc(docRef);
|
|
73
126
|
return true;
|
|
74
127
|
} catch {
|
|
@@ -81,16 +134,10 @@ export class CreationsRepository implements ICreationsRepository {
|
|
|
81
134
|
creationId: string,
|
|
82
135
|
isShared: boolean,
|
|
83
136
|
): Promise<boolean> {
|
|
84
|
-
|
|
137
|
+
const docRef = this.getDocRef(userId, creationId);
|
|
138
|
+
if (!docRef) return false;
|
|
85
139
|
|
|
86
140
|
try {
|
|
87
|
-
const docRef = doc(
|
|
88
|
-
this.db,
|
|
89
|
-
"users",
|
|
90
|
-
userId,
|
|
91
|
-
this.collectionName,
|
|
92
|
-
creationId,
|
|
93
|
-
);
|
|
94
141
|
await updateDoc(docRef, { isShared });
|
|
95
142
|
return true;
|
|
96
143
|
} catch {
|
package/src/types.d.ts
CHANGED
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
* Type declarations for external modules
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
declare module "@umituz/react-native-firestore" {
|
|
6
|
+
import type { Firestore } from "firebase/firestore";
|
|
7
|
+
|
|
8
|
+
export class BaseRepository {
|
|
9
|
+
protected getDb(): Firestore | null;
|
|
10
|
+
protected getDbOrThrow(): Firestore;
|
|
11
|
+
protected isDbInitialized(): boolean;
|
|
12
|
+
protected isQuotaError(error: unknown): boolean;
|
|
13
|
+
protected handleQuotaError(error: unknown): never;
|
|
14
|
+
protected executeWithQuotaHandling<T>(
|
|
15
|
+
operation: () => Promise<T>,
|
|
16
|
+
): Promise<T>;
|
|
17
|
+
protected trackRead(
|
|
18
|
+
collection: string,
|
|
19
|
+
count: number,
|
|
20
|
+
cached: boolean,
|
|
21
|
+
): void;
|
|
22
|
+
protected trackWrite(
|
|
23
|
+
collection: string,
|
|
24
|
+
docId: string,
|
|
25
|
+
count: number,
|
|
26
|
+
): void;
|
|
27
|
+
protected trackDelete(
|
|
28
|
+
collection: string,
|
|
29
|
+
docId: string,
|
|
30
|
+
count: number,
|
|
31
|
+
): void;
|
|
32
|
+
destroy(): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getFirestore(): Firestore | null;
|
|
36
|
+
export function initializeFirestore(app: unknown): void;
|
|
37
|
+
export function isFirestoreInitialized(): boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
5
40
|
declare module "@umituz/react-native-design-system" {
|
|
6
41
|
import type { FC, ReactNode } from "react";
|
|
7
42
|
import type { StyleProp, ViewStyle, TextStyle } from "react-native";
|