@umituz/react-native-firebase 2.6.3 → 2.6.5

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.
Files changed (108) hide show
  1. package/package.json +1 -1
  2. package/src/application/auth/index.ts +2 -34
  3. package/src/application/auth/use-cases/index.ts +1 -21
  4. package/src/domains/account-deletion/domain/index.ts +1 -8
  5. package/src/domains/account-deletion/index.ts +0 -42
  6. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor.ts +79 -0
  7. package/src/domains/account-deletion/infrastructure/services/AccountDeletionTypes.ts +0 -1
  8. package/src/domains/account-deletion/infrastructure/services/account-deletion.service.ts +2 -14
  9. package/src/domains/auth/index.ts +3 -12
  10. package/src/domains/auth/infrastructure/config/FirebaseAuthClient.ts +48 -60
  11. package/src/domains/auth/infrastructure/config/index.ts +2 -0
  12. package/src/domains/auth/infrastructure/config/initializers/index.ts +1 -0
  13. package/src/domains/auth/infrastructure/services/index.ts +16 -0
  14. package/src/domains/auth/infrastructure/services/utils/index.ts +1 -0
  15. package/src/domains/auth/infrastructure/stores/index.ts +1 -0
  16. package/src/domains/auth/infrastructure/utils/index.ts +1 -0
  17. package/src/domains/auth/infrastructure.ts +11 -0
  18. package/src/domains/auth/presentation/hooks/useGoogleOAuth.ts +18 -59
  19. package/src/domains/firestore/domain/entities/Collection.ts +0 -2
  20. package/src/domains/firestore/domain/index.ts +6 -2
  21. package/src/domains/firestore/domain/value-objects/WhereClause.ts +0 -14
  22. package/src/domains/firestore/index.ts +0 -1
  23. package/src/domains/firestore/infrastructure/config/FirestoreClient.ts +42 -60
  24. package/src/domains/firestore/presentation/hooks/useFirestoreMutation.ts +1 -1
  25. package/src/domains/firestore/presentation/hooks/useFirestoreQuery.ts +1 -1
  26. package/src/shared/infrastructure/base/ErrorHandler.ts +81 -0
  27. package/src/shared/infrastructure/base/ServiceBase.ts +62 -0
  28. package/src/shared/infrastructure/config/base/ServiceClientSingleton.ts +39 -0
  29. package/src/application/auth/ports/AuthPort.ts.bak +0 -164
  30. package/src/application/auth/ports/AuthPort_part_aa +0 -150
  31. package/src/application/auth/ports/AuthPort_part_ab +0 -14
  32. package/src/application/auth/use-cases/SignInUseCase.ts.bak +0 -253
  33. package/src/application/auth/use-cases/SignInUseCaseHelpers.ts +0 -0
  34. package/src/application/auth/use-cases/SignInUseCaseMain.ts +0 -0
  35. package/src/application/auth/use-cases/SignInUseCase_part_aa +0 -150
  36. package/src/application/auth/use-cases/SignInUseCase_part_ab +0 -103
  37. package/src/application/auth/use-cases/SignOutUseCase.ts.bak +0 -288
  38. package/src/application/auth/use-cases/SignOutUseCaseCleanup.ts +0 -0
  39. package/src/application/auth/use-cases/SignOutUseCaseMain.ts +0 -0
  40. package/src/application/auth/use-cases/SignOutUseCase_part_aa +0 -150
  41. package/src/application/auth/use-cases/SignOutUseCase_part_ab +0 -138
  42. package/src/domains/account-deletion/domain/services/UserValidationHelpers.ts.bak +0 -181
  43. package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_aa +0 -150
  44. package/src/domains/account-deletion/domain/services/UserValidationHelpers_part_ab +0 -31
  45. package/src/domains/account-deletion/domain/services/UserValidationService.ts.bak +0 -286
  46. package/src/domains/account-deletion/domain/services/UserValidationService_part_aa +0 -150
  47. package/src/domains/account-deletion/domain/services/UserValidationService_part_ab +0 -136
  48. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor.ts.bak +0 -230
  49. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_aa +0 -150
  50. package/src/domains/account-deletion/infrastructure/services/AccountDeletionExecutor_part_ab +0 -80
  51. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler.ts.bak +0 -174
  52. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_aa +0 -150
  53. package/src/domains/account-deletion/infrastructure/services/AccountDeletionReauthHandler_part_ab +0 -24
  54. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository.ts.bak +0 -266
  55. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_aa +0 -150
  56. package/src/domains/account-deletion/infrastructure/services/AccountDeletionRepository_part_ab +0 -116
  57. package/src/domains/account-deletion/infrastructure/services/reauthentication.service.ts.bak +0 -160
  58. package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_aa +0 -150
  59. package/src/domains/account-deletion/infrastructure/services/reauthentication.service_part_ab +0 -10
  60. package/src/domains/auth/infrastructure.ts.bak +0 -156
  61. package/src/domains/auth/infrastructure_part_aa +0 -150
  62. package/src/domains/auth/infrastructure_part_ab +0 -6
  63. package/src/domains/auth/presentation/hooks/GoogleOAuthHelpers.ts +0 -0
  64. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService.ts.bak +0 -247
  65. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_aa +0 -150
  66. package/src/domains/auth/presentation/hooks/GoogleOAuthHookService_part_ab +0 -97
  67. package/src/domains/auth/presentation/hooks/GoogleOAuthService.ts +0 -0
  68. package/src/domains/firestore/domain/entities/Collection.ts.bak +0 -288
  69. package/src/domains/firestore/domain/entities/Collection_part_aa +0 -150
  70. package/src/domains/firestore/domain/entities/Collection_part_ab +0 -138
  71. package/src/domains/firestore/domain/entities/Document.ts.bak +0 -233
  72. package/src/domains/firestore/domain/entities/DocumentHelpers.ts +0 -0
  73. package/src/domains/firestore/domain/entities/DocumentMain.ts +0 -0
  74. package/src/domains/firestore/domain/entities/Document_part_aa +0 -150
  75. package/src/domains/firestore/domain/entities/Document_part_ab +0 -83
  76. package/src/domains/firestore/domain/services/QueryService.ts.bak +0 -182
  77. package/src/domains/firestore/domain/services/QueryServiceAnalysis.ts.bak +0 -169
  78. package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_aa +0 -150
  79. package/src/domains/firestore/domain/services/QueryServiceAnalysis_part_ab +0 -19
  80. package/src/domains/firestore/domain/services/QueryServiceHelpers.ts.bak +0 -151
  81. package/src/domains/firestore/domain/services/QueryServiceHelpers_part_aa +0 -150
  82. package/src/domains/firestore/domain/services/QueryServiceHelpers_part_ab +0 -1
  83. package/src/domains/firestore/domain/services/QueryService_part_aa +0 -150
  84. package/src/domains/firestore/domain/services/QueryService_part_ab +0 -32
  85. package/src/domains/firestore/domain/value-objects/QueryOptions.ts.bak +0 -191
  86. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization.ts.bak +0 -207
  87. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_aa +0 -150
  88. package/src/domains/firestore/domain/value-objects/QueryOptionsSerialization_part_ab +0 -57
  89. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation.ts.bak +0 -182
  90. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_aa +0 -150
  91. package/src/domains/firestore/domain/value-objects/QueryOptionsValidation_part_ab +0 -32
  92. package/src/domains/firestore/domain/value-objects/QueryOptions_part_aa +0 -150
  93. package/src/domains/firestore/domain/value-objects/QueryOptions_part_ab +0 -41
  94. package/src/domains/firestore/domain/value-objects/WhereClause.ts.bak +0 -299
  95. package/src/domains/firestore/domain/value-objects/WhereClauseFactory.ts.bak +0 -207
  96. package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_aa +0 -150
  97. package/src/domains/firestore/domain/value-objects/WhereClauseFactory_part_ab +0 -57
  98. package/src/domains/firestore/domain/value-objects/WhereClause_part_aa +0 -150
  99. package/src/domains/firestore/domain/value-objects/WhereClause_part_ab +0 -149
  100. package/src/shared/infrastructure/base/ErrorHandler.ts.bak +0 -189
  101. package/src/shared/infrastructure/base/ErrorHandler_part_aa +0 -150
  102. package/src/shared/infrastructure/base/ErrorHandler_part_ab +0 -39
  103. package/src/shared/infrastructure/base/ServiceBase.ts.bak +0 -220
  104. package/src/shared/infrastructure/base/ServiceBase_part_aa +0 -150
  105. package/src/shared/infrastructure/base/ServiceBase_part_ab +0 -70
  106. package/src/shared/infrastructure/config/base/ServiceClientSingleton.ts.bak +0 -155
  107. package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_aa +0 -150
  108. package/src/shared/infrastructure/config/base/ServiceClientSingleton_part_ab +0 -5
@@ -1,97 +0,0 @@
1
- if (!this.isAvailable()) {
2
- return {
3
- valid: false,
4
- error: 'expo-auth-session is not available. Please install expo-auth-session and expo-web-browser.',
5
- };
6
- }
7
-
8
- if (!this.isConfigured()) {
9
- return {
10
- valid: false,
11
- error: 'Google Sign-In is not configured. Please provide valid client IDs.',
12
- };
13
- }
14
-
15
- return { valid: true };
16
- }
17
-
18
- /**
19
- * Get error message from error
20
- */
21
- getErrorMessage(error: unknown): string {
22
- if (error instanceof Error) {
23
- return error.message;
24
- }
25
- return 'Google sign-in failed';
26
- }
27
-
28
- /**
29
- * Check if response is successful
30
- */
31
- isSuccessfulResponse(response: AuthSessionResponse | null): boolean {
32
- return response?.type === 'success' && !!response.authentication?.idToken;
33
- }
34
-
35
- /**
36
- * Check if response is error
37
- */
38
- isErrorResponse(response: AuthSessionResponse | null): boolean {
39
- return response?.type === 'error';
40
- }
41
-
42
- /**
43
- * Extract ID token from response
44
- */
45
- extractIdToken(response: AuthSessionResponse | null): string | null {
46
- return response?.authentication?.idToken || null;
47
- }
48
-
49
- /**
50
- * Create error result
51
- */
52
- createErrorResult(error: string): { success: false; error: string } {
53
- return { success: false, error };
54
- }
55
-
56
- /**
57
- * Check if auth request is ready
58
- */
59
- isReady(): boolean {
60
- const [request, , promptAsync] = this.authRequest;
61
- return request !== null && promptAsync !== null;
62
- }
63
-
64
- /**
65
- * Get configuration
66
- */
67
- getConfig(): GoogleOAuthConfig | undefined {
68
- return this.config;
69
- }
70
-
71
- /**
72
- * Reset service state
73
- */
74
- reset(): void {
75
- this.config = undefined;
76
- }
77
- }
78
-
79
- /**
80
- * Factory function to create Google OAuth hook service
81
- */
82
- export function createGoogleOAuthHookService(config?: GoogleOAuthConfig): GoogleOAuthHookService {
83
- return new GoogleOAuthHookService(config);
84
- }
85
-
86
- /**
87
- * Check if expo-auth-session is available
88
- * Useful for conditional rendering
89
- */
90
- export function isExpoAuthSessionAvailable(): boolean {
91
- return isExpoAuthAvailable;
92
- }
93
-
94
- /**
95
- * Re-export types for convenience
96
- */
97
- export type { AuthSessionResponse, ExpoAuthSessionModule };
@@ -1,288 +0,0 @@
1
- /**
2
- * Collection Entity
3
- * Single Responsibility: Represent a Firestore collection with metadata
4
- *
5
- * Domain entity that encapsulates collection information and metadata.
6
- * Provides business logic for collection operations.
7
- *
8
- * Max lines: 150 (enforced for maintainability)
9
- */
10
-
11
- import type { CollectionReference, Query } from 'firebase/firestore';
12
- import type { Document } from './Document';
13
-
14
- /**
15
- * Collection metadata
16
- */
17
- export interface CollectionMetadata {
18
- readonly name: string;
19
- readonly path: string;
20
- readonly parentPath?: string;
21
- }
22
-
23
- /**
24
- * Collection entity
25
- * Represents a Firestore collection with metadata
26
- */
27
- export class Collection<TDocument = unknown> {
28
- readonly name: string;
29
- readonly path: string;
30
- readonly parentPath: string | undefined;
31
- private readonly reference: CollectionReference<TDocument> | Query<TDocument>;
32
-
33
- constructor(
34
- reference: CollectionReference<TDocument> | Query<TDocument>,
35
- metadata: CollectionMetadata
36
- ) {
37
- this.reference = reference;
38
- this.name = metadata.name;
39
- this.path = metadata.path;
40
- this.parentPath = metadata.parentPath || undefined;
41
- }
42
-
43
- /**
44
- * Create collection from collection reference
45
- */
46
- static fromReference<TDocument = unknown>(
47
- reference: CollectionReference<TDocument>
48
- ): Collection<TDocument> {
49
- return new Collection(reference, {
50
- name: reference.id,
51
- path: reference.path,
52
- parentPath: reference.parent?.path || null,
53
- });
54
- }
55
-
56
- /**
57
- * Create collection from query
58
- */
59
- static fromQuery<TDocument = unknown>(query: Query<TDocument>, name: string, path: string): Collection<TDocument> {
60
- return new Collection(query, {
61
- name,
62
- path,
63
- parentPath: path.split('/').slice(0, -2).join('/') || null,
64
- });
65
- }
66
-
67
- /**
68
- * Get collection name
69
- */
70
- getName(): string {
71
- return this.name;
72
- }
73
-
74
- /**
75
- * Get collection path
76
- */
77
- getPath(): string {
78
- return this.path;
79
- }
80
-
81
- /**
82
- * Get parent path if exists
83
- */
84
- getParentPath(): string | null {
85
- return this.parentPath;
86
- }
87
-
88
- /**
89
- * Check if collection is nested (has parent)
90
- */
91
- isNested(): boolean {
92
- return this.parentPath !== null;
93
- }
94
-
95
- /**
96
- * Check if collection is root level (no parent)
97
- */
98
- isRootLevel(): boolean {
99
- return this.parentPath === null;
100
- }
101
-
102
- /**
103
- * Get collection depth in hierarchy
104
- * Root collections have depth 0
105
- */
106
- getDepth(): number {
107
- if (!this.parentPath) return 0;
108
- return this.path.split('/').length / 2 - 1;
109
- }
110
-
111
- /**
112
- * Get the underlying reference
113
- */
114
- getReference(): CollectionReference<TDocument> | Query<TDocument> {
115
- return this.reference;
116
- }
117
-
118
- /**
119
- * Check if collection is a query (has filters/limits)
120
- */
121
- isQuery(): boolean {
122
- return 'type' in this.reference && this.reference.type === 'query';
123
- }
124
-
125
- /**
126
- * Check if collection is a collection reference (no filters)
127
- */
128
- isCollectionReference(): boolean {
129
- return !this.isQuery();
130
- }
131
-
132
- /**
133
- * Validate collection name format
134
- * Collection names must match Firestore requirements
135
- */
136
- static isValidName(name: string): boolean {
137
- // Collection names must be non-empty strings
138
- if (!name || typeof name !== 'string' || name.trim() === '') {
139
- return false;
140
- }
141
-
142
- // Cannot contain special characters
143
- const invalidChars = /[\/\\.\s]/;
144
- if (invalidChars.test(name)) {
145
- return false;
146
- }
147
-
148
- // Cannot start or end with double underscore
149
- if (name.startsWith('__') || name.endsWith('__')) {
150
- return false;
151
- }
152
-
153
- // Reasonable length limit
154
- if (name.length > 100) {
155
- return false;
156
- }
157
-
158
- return true;
159
- }
160
-
161
- /**
162
- * Validate collection path format
163
- * Paths must follow Firestore path structure
164
- */
165
- static isValidPath(path: string): boolean {
166
- if (!path || typeof path !== 'string' || path.trim() === '') {
167
- return false;
168
- }
169
-
170
- const segments = path.split('/');
171
- if (segments.length < 2 || segments.length % 2 !== 0) {
172
- return false;
173
- }
174
-
175
- return segments.every(segment => this.isValidName(segment));
176
- }
177
-
178
- /**
179
- * Extract collection name from path
180
- */
181
- static extractNameFromPath(path: string): string | null {
182
- if (!this.isValidPath(path)) {
183
- return null;
184
- }
185
-
186
- const segments = path.split('/');
187
- return segments[segments.length - 1] || null;
188
- }
189
-
190
- /**
191
- * Extract parent path from collection path
192
- */
193
- static extractParentPath(path: string): string | null {
194
- if (!this.isValidPath(path)) {
195
- return null;
196
- }
197
-
198
- const segments = path.split('/');
199
- if (segments.length <= 2) {
200
- return null;
201
- }
202
-
203
- return segments.slice(0, -1).join('/');
204
- }
205
-
206
- /**
207
- * Convert to plain object (for serialization)
208
- */
209
- toObject(): CollectionMetadata {
210
- return {
211
- name: this.name,
212
- path: this.path,
213
- parentPath: this.parentPath || undefined,
214
- };
215
- }
216
-
217
- /**
218
- * Create a sub-collection path
219
- */
220
- createSubCollectionPath(subCollectionName: string): string | null {
221
- if (!Collection.isValidName(subCollectionName)) {
222
- return null;
223
- }
224
-
225
- return `${this.path}/${subCollectionName}`;
226
- }
227
-
228
- /**
229
- * Check if collection is a sub-collection of another
230
- */
231
- isSubCollectionOf(other: Collection): boolean {
232
- return this.parentPath === other.path;
233
- }
234
-
235
- /**
236
- * Check if collection is parent of another
237
- */
238
- isParentOf(other: Collection): boolean {
239
- return other.isSubCollectionOf(this);
240
- }
241
-
242
- /**
243
- * Get collection ID (similar to name but more explicit)
244
- */
245
- getId(): string {
246
- return this.name;
247
- }
248
-
249
- /**
250
- * Check if this is a user collection (users/{userId}/{collection})
251
- */
252
- isUserCollection(): boolean {
253
- return this.parentPath?.startsWith('users/') || false;
254
- }
255
-
256
- /**
257
- * Extract user ID from user collection path
258
- * Returns null if not a user collection
259
- */
260
- extractUserId(): string | null {
261
- if (!this.isUserCollection()) return null;
262
-
263
- const segments = this.path.split('/');
264
- if (segments.length >= 3 && segments[0] === 'users') {
265
- return segments[1];
266
- }
267
-
268
- return null;
269
- }
270
- }
271
-
272
- /**
273
- * Factory function to create collection entity
274
- */
275
- export function createCollection<TDocument = unknown>(
276
- reference: CollectionReference<TDocument> | Query<TDocument>,
277
- name?: string,
278
- path?: string
279
- ): Collection<TDocument> {
280
- if ('type' in reference && reference.type === 'query') {
281
- if (!name || !path) {
282
- throw new Error('name and path are required for query collections');
283
- }
284
- return Collection.fromQuery(reference, name, path);
285
- }
286
-
287
- return Collection.fromReference(reference as CollectionReference<TDocument>);
288
- }
@@ -1,150 +0,0 @@
1
- /**
2
- * Collection Entity
3
- * Single Responsibility: Represent a Firestore collection with metadata
4
- *
5
- * Domain entity that encapsulates collection information and metadata.
6
- * Provides business logic for collection operations.
7
- *
8
- * Max lines: 150 (enforced for maintainability)
9
- */
10
-
11
- import type { CollectionReference, Query } from 'firebase/firestore';
12
- import type { Document } from './Document';
13
-
14
- /**
15
- * Collection metadata
16
- */
17
- export interface CollectionMetadata {
18
- readonly name: string;
19
- readonly path: string;
20
- readonly parentPath?: string;
21
- }
22
-
23
- /**
24
- * Collection entity
25
- * Represents a Firestore collection with metadata
26
- */
27
- export class Collection<TDocument = unknown> {
28
- readonly name: string;
29
- readonly path: string;
30
- readonly parentPath: string | undefined;
31
- private readonly reference: CollectionReference<TDocument> | Query<TDocument>;
32
-
33
- constructor(
34
- reference: CollectionReference<TDocument> | Query<TDocument>,
35
- metadata: CollectionMetadata
36
- ) {
37
- this.reference = reference;
38
- this.name = metadata.name;
39
- this.path = metadata.path;
40
- this.parentPath = metadata.parentPath || undefined;
41
- }
42
-
43
- /**
44
- * Create collection from collection reference
45
- */
46
- static fromReference<TDocument = unknown>(
47
- reference: CollectionReference<TDocument>
48
- ): Collection<TDocument> {
49
- return new Collection(reference, {
50
- name: reference.id,
51
- path: reference.path,
52
- parentPath: reference.parent?.path || null,
53
- });
54
- }
55
-
56
- /**
57
- * Create collection from query
58
- */
59
- static fromQuery<TDocument = unknown>(query: Query<TDocument>, name: string, path: string): Collection<TDocument> {
60
- return new Collection(query, {
61
- name,
62
- path,
63
- parentPath: path.split('/').slice(0, -2).join('/') || null,
64
- });
65
- }
66
-
67
- /**
68
- * Get collection name
69
- */
70
- getName(): string {
71
- return this.name;
72
- }
73
-
74
- /**
75
- * Get collection path
76
- */
77
- getPath(): string {
78
- return this.path;
79
- }
80
-
81
- /**
82
- * Get parent path if exists
83
- */
84
- getParentPath(): string | null {
85
- return this.parentPath;
86
- }
87
-
88
- /**
89
- * Check if collection is nested (has parent)
90
- */
91
- isNested(): boolean {
92
- return this.parentPath !== null;
93
- }
94
-
95
- /**
96
- * Check if collection is root level (no parent)
97
- */
98
- isRootLevel(): boolean {
99
- return this.parentPath === null;
100
- }
101
-
102
- /**
103
- * Get collection depth in hierarchy
104
- * Root collections have depth 0
105
- */
106
- getDepth(): number {
107
- if (!this.parentPath) return 0;
108
- return this.path.split('/').length / 2 - 1;
109
- }
110
-
111
- /**
112
- * Get the underlying reference
113
- */
114
- getReference(): CollectionReference<TDocument> | Query<TDocument> {
115
- return this.reference;
116
- }
117
-
118
- /**
119
- * Check if collection is a query (has filters/limits)
120
- */
121
- isQuery(): boolean {
122
- return 'type' in this.reference && this.reference.type === 'query';
123
- }
124
-
125
- /**
126
- * Check if collection is a collection reference (no filters)
127
- */
128
- isCollectionReference(): boolean {
129
- return !this.isQuery();
130
- }
131
-
132
- /**
133
- * Validate collection name format
134
- * Collection names must match Firestore requirements
135
- */
136
- static isValidName(name: string): boolean {
137
- // Collection names must be non-empty strings
138
- if (!name || typeof name !== 'string' || name.trim() === '') {
139
- return false;
140
- }
141
-
142
- // Cannot contain special characters
143
- const invalidChars = /[\/\\.\s]/;
144
- if (invalidChars.test(name)) {
145
- return false;
146
- }
147
-
148
- // Cannot start or end with double underscore
149
- if (name.startsWith('__') || name.endsWith('__')) {
150
- return false;
@@ -1,138 +0,0 @@
1
- }
2
-
3
- // Reasonable length limit
4
- if (name.length > 100) {
5
- return false;
6
- }
7
-
8
- return true;
9
- }
10
-
11
- /**
12
- * Validate collection path format
13
- * Paths must follow Firestore path structure
14
- */
15
- static isValidPath(path: string): boolean {
16
- if (!path || typeof path !== 'string' || path.trim() === '') {
17
- return false;
18
- }
19
-
20
- const segments = path.split('/');
21
- if (segments.length < 2 || segments.length % 2 !== 0) {
22
- return false;
23
- }
24
-
25
- return segments.every(segment => this.isValidName(segment));
26
- }
27
-
28
- /**
29
- * Extract collection name from path
30
- */
31
- static extractNameFromPath(path: string): string | null {
32
- if (!this.isValidPath(path)) {
33
- return null;
34
- }
35
-
36
- const segments = path.split('/');
37
- return segments[segments.length - 1] || null;
38
- }
39
-
40
- /**
41
- * Extract parent path from collection path
42
- */
43
- static extractParentPath(path: string): string | null {
44
- if (!this.isValidPath(path)) {
45
- return null;
46
- }
47
-
48
- const segments = path.split('/');
49
- if (segments.length <= 2) {
50
- return null;
51
- }
52
-
53
- return segments.slice(0, -1).join('/');
54
- }
55
-
56
- /**
57
- * Convert to plain object (for serialization)
58
- */
59
- toObject(): CollectionMetadata {
60
- return {
61
- name: this.name,
62
- path: this.path,
63
- parentPath: this.parentPath || undefined,
64
- };
65
- }
66
-
67
- /**
68
- * Create a sub-collection path
69
- */
70
- createSubCollectionPath(subCollectionName: string): string | null {
71
- if (!Collection.isValidName(subCollectionName)) {
72
- return null;
73
- }
74
-
75
- return `${this.path}/${subCollectionName}`;
76
- }
77
-
78
- /**
79
- * Check if collection is a sub-collection of another
80
- */
81
- isSubCollectionOf(other: Collection): boolean {
82
- return this.parentPath === other.path;
83
- }
84
-
85
- /**
86
- * Check if collection is parent of another
87
- */
88
- isParentOf(other: Collection): boolean {
89
- return other.isSubCollectionOf(this);
90
- }
91
-
92
- /**
93
- * Get collection ID (similar to name but more explicit)
94
- */
95
- getId(): string {
96
- return this.name;
97
- }
98
-
99
- /**
100
- * Check if this is a user collection (users/{userId}/{collection})
101
- */
102
- isUserCollection(): boolean {
103
- return this.parentPath?.startsWith('users/') || false;
104
- }
105
-
106
- /**
107
- * Extract user ID from user collection path
108
- * Returns null if not a user collection
109
- */
110
- extractUserId(): string | null {
111
- if (!this.isUserCollection()) return null;
112
-
113
- const segments = this.path.split('/');
114
- if (segments.length >= 3 && segments[0] === 'users') {
115
- return segments[1];
116
- }
117
-
118
- return null;
119
- }
120
- }
121
-
122
- /**
123
- * Factory function to create collection entity
124
- */
125
- export function createCollection<TDocument = unknown>(
126
- reference: CollectionReference<TDocument> | Query<TDocument>,
127
- name?: string,
128
- path?: string
129
- ): Collection<TDocument> {
130
- if ('type' in reference && reference.type === 'query') {
131
- if (!name || !path) {
132
- throw new Error('name and path are required for query collections');
133
- }
134
- return Collection.fromQuery(reference, name, path);
135
- }
136
-
137
- return Collection.fromReference(reference as CollectionReference<TDocument>);
138
- }