@fyrestack/database 0.1.0 → 0.1.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/dist/index.cjs +1229 -0
- package/dist/index.d.cts +1071 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +1071 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1179 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +2 -2
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1071 @@
|
|
|
1
|
+
import { OmitPrivate, Prettify, Type } from "@fyrestack/core";
|
|
2
|
+
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/batch.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Maximum operations per Firestore batch.
|
|
7
|
+
*/
|
|
8
|
+
declare const MAX_BATCH_SIZE = 500;
|
|
9
|
+
/**
|
|
10
|
+
* Run operations within a write batch.
|
|
11
|
+
*
|
|
12
|
+
* Batches provide:
|
|
13
|
+
* - Atomic writes (all succeed or all fail)
|
|
14
|
+
* - Better performance than individual writes
|
|
15
|
+
* - Up to 500 operations per batch
|
|
16
|
+
* - Works across multiple repositories
|
|
17
|
+
*
|
|
18
|
+
* The batch context is **automatically propagated** to all repository
|
|
19
|
+
* methods called within the batch function - no need to pass context explicitly.
|
|
20
|
+
*
|
|
21
|
+
* Note: Batches are write-only. Use `runTransaction` if you need reads.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Bulk create users
|
|
26
|
+
* await writeBatch(async () => {
|
|
27
|
+
* for (const user of users) {
|
|
28
|
+
* await UserRepo.save({}, user);
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // Cross-repository batch write
|
|
36
|
+
* await writeBatch(async () => {
|
|
37
|
+
* await UserRepo.save({}, user);
|
|
38
|
+
* await ProfileRepo.save({ userId: user.id }, profile);
|
|
39
|
+
* await AuditRepo.save({}, auditLog);
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @param fn - Async function to run within the batch
|
|
44
|
+
*/
|
|
45
|
+
declare function writeBatch(fn: () => Promise<void>): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Run operations with automatic batch chunking for large datasets.
|
|
48
|
+
*
|
|
49
|
+
* Automatically commits and creates new batches when exceeding 500 operations.
|
|
50
|
+
* Useful for migrations or bulk imports with thousands of records.
|
|
51
|
+
*
|
|
52
|
+
* The batch context is **automatically propagated** to all repository
|
|
53
|
+
* methods called within the function.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* // Process 10,000 records with automatic batching
|
|
58
|
+
* await writeChunkedBatch(async () => {
|
|
59
|
+
* for (const user of thousandsOfUsers) {
|
|
60
|
+
* await UserRepo.save({}, user);
|
|
61
|
+
* // Automatically commits every 500 operations
|
|
62
|
+
* }
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @param fn - Function to run with automatic batch chunking
|
|
67
|
+
*/
|
|
68
|
+
declare function writeChunkedBatch(fn: () => Promise<void>): Promise<void>;
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/firestore.types.d.ts
|
|
71
|
+
/**
|
|
72
|
+
* Sentinel type for server-generated timestamps.
|
|
73
|
+
* This is a branded type that represents Firebase's serverTimestamp() value.
|
|
74
|
+
*/
|
|
75
|
+
interface ServerTimestampSentinel {
|
|
76
|
+
/** Brand to distinguish from other objects */
|
|
77
|
+
readonly __type__: 'serverTimestamp';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Type guard to check if a value is a ServerTimestampSentinel.
|
|
81
|
+
* Note: This checks the runtime structure, not the brand.
|
|
82
|
+
*/
|
|
83
|
+
declare function isServerTimestamp(value: unknown): value is ServerTimestampSentinel;
|
|
84
|
+
/**
|
|
85
|
+
* Abstract document snapshot
|
|
86
|
+
*/
|
|
87
|
+
interface DocumentSnapshot<T = unknown> {
|
|
88
|
+
id: string;
|
|
89
|
+
exists: boolean;
|
|
90
|
+
data(): T | undefined;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Abstract document reference
|
|
94
|
+
*/
|
|
95
|
+
interface DocumentReference<T = unknown> {
|
|
96
|
+
id: string;
|
|
97
|
+
path: string;
|
|
98
|
+
/** Native reference for transaction/batch operations (internal use) */
|
|
99
|
+
_native?: unknown;
|
|
100
|
+
get(): Promise<DocumentSnapshot<T>>;
|
|
101
|
+
set(data: T): Promise<void>;
|
|
102
|
+
update(data: Record<string, unknown>): Promise<void>;
|
|
103
|
+
delete(): Promise<void>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Abstract query snapshot
|
|
107
|
+
*/
|
|
108
|
+
interface QuerySnapshot<T = unknown> {
|
|
109
|
+
docs: DocumentSnapshot<T>[];
|
|
110
|
+
empty: boolean;
|
|
111
|
+
size: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Supported Firestore operators
|
|
115
|
+
*/
|
|
116
|
+
type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains' | 'array-contains-any' | 'in' | 'not-in';
|
|
117
|
+
/**
|
|
118
|
+
* Sort direction
|
|
119
|
+
*/
|
|
120
|
+
type OrderByDirection = 'asc' | 'desc';
|
|
121
|
+
/**
|
|
122
|
+
* Abstract query reference - chainable query builder
|
|
123
|
+
*/
|
|
124
|
+
interface QueryReference<T = unknown> {
|
|
125
|
+
where(field: string, op: WhereFilterOp, value: unknown): QueryReference<T>;
|
|
126
|
+
orderBy(field: string, direction?: OrderByDirection): QueryReference<T>;
|
|
127
|
+
limit(count: number): QueryReference<T>;
|
|
128
|
+
startAt(...values: unknown[]): QueryReference<T>;
|
|
129
|
+
startAfter(...values: unknown[]): QueryReference<T>;
|
|
130
|
+
endAt(...values: unknown[]): QueryReference<T>;
|
|
131
|
+
endBefore(...values: unknown[]): QueryReference<T>;
|
|
132
|
+
get(): Promise<QuerySnapshot<T>>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Abstract collection reference
|
|
136
|
+
*/
|
|
137
|
+
interface CollectionReference<T = unknown> extends QueryReference<T> {
|
|
138
|
+
path: string;
|
|
139
|
+
doc(id?: string): DocumentReference<T>;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Options for running a transaction.
|
|
143
|
+
*/
|
|
144
|
+
interface TransactionOptions {
|
|
145
|
+
/** Maximum retry attempts on contention (default: 5) */
|
|
146
|
+
maxAttempts?: number;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Firestore Transaction handle for atomic read-write operations.
|
|
150
|
+
* All reads must happen before writes within a transaction.
|
|
151
|
+
*/
|
|
152
|
+
interface Transaction {
|
|
153
|
+
/**
|
|
154
|
+
* Read a document within the transaction.
|
|
155
|
+
*/
|
|
156
|
+
get<T>(docRef: DocumentReference<T>): Promise<DocumentSnapshot<T>>;
|
|
157
|
+
/**
|
|
158
|
+
* Set a document within the transaction.
|
|
159
|
+
*/
|
|
160
|
+
set<T>(docRef: DocumentReference<T>, data: T): Transaction;
|
|
161
|
+
/**
|
|
162
|
+
* Update a document within the transaction.
|
|
163
|
+
*/
|
|
164
|
+
update(docRef: DocumentReference, data: Record<string, unknown>): Transaction;
|
|
165
|
+
/**
|
|
166
|
+
* Delete a document within the transaction.
|
|
167
|
+
*/
|
|
168
|
+
delete(docRef: DocumentReference): Transaction;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Firestore WriteBatch handle for atomic write-only operations.
|
|
172
|
+
* Up to 500 operations per batch.
|
|
173
|
+
*/
|
|
174
|
+
interface WriteBatch {
|
|
175
|
+
/**
|
|
176
|
+
* Set a document in the batch.
|
|
177
|
+
*/
|
|
178
|
+
set<T>(docRef: DocumentReference<T>, data: T): WriteBatch;
|
|
179
|
+
/**
|
|
180
|
+
* Update a document in the batch.
|
|
181
|
+
*/
|
|
182
|
+
update(docRef: DocumentReference, data: Record<string, unknown>): WriteBatch;
|
|
183
|
+
/**
|
|
184
|
+
* Delete a document in the batch.
|
|
185
|
+
*/
|
|
186
|
+
delete(docRef: DocumentReference): WriteBatch;
|
|
187
|
+
/**
|
|
188
|
+
* Commit all batched operations atomically.
|
|
189
|
+
*/
|
|
190
|
+
commit(): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Abstract Firestore instance - the main DI interface
|
|
194
|
+
*/
|
|
195
|
+
interface FirestoreAdapter {
|
|
196
|
+
collection<T = unknown>(path: string): CollectionReference<T>;
|
|
197
|
+
doc<T = unknown>(path: string): DocumentReference<T>;
|
|
198
|
+
/**
|
|
199
|
+
* Returns a sentinel value for server-generated timestamp.
|
|
200
|
+
* Used for createdAt/updatedAt fields.
|
|
201
|
+
*
|
|
202
|
+
* Note: Returns the actual Firebase sentinel value which is cast to
|
|
203
|
+
* ServerTimestampSentinel for type safety. The runtime value is
|
|
204
|
+
* Firebase's internal FieldValue/serverTimestamp implementation.
|
|
205
|
+
*/
|
|
206
|
+
serverTimestamp(): ServerTimestampSentinel;
|
|
207
|
+
/**
|
|
208
|
+
* Run a transaction with automatic retry on conflicts.
|
|
209
|
+
* @param updateFn - Function receiving Transaction object
|
|
210
|
+
* @param options - Transaction options (maxAttempts, etc.)
|
|
211
|
+
*/
|
|
212
|
+
runTransaction<T>(updateFn: (transaction: Transaction) => Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
213
|
+
/**
|
|
214
|
+
* Create a new write batch.
|
|
215
|
+
*/
|
|
216
|
+
batch(): WriteBatch;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Set the Firestore adapter to use (call once at app initialization)
|
|
220
|
+
*/
|
|
221
|
+
declare function setFirestoreAdapter(adapter: FirestoreAdapter): void;
|
|
222
|
+
/**
|
|
223
|
+
* Get the current Firestore adapter
|
|
224
|
+
* @throws AdapterNotInitializedError if adapter not initialized
|
|
225
|
+
*/
|
|
226
|
+
declare function getFirestoreAdapter(): FirestoreAdapter;
|
|
227
|
+
/**
|
|
228
|
+
* Reset the Firestore adapter (for testing only)
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
declare function _resetFirestoreAdapter(): void;
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/context.d.ts
|
|
234
|
+
/**
|
|
235
|
+
* Transaction context - supports reads and writes.
|
|
236
|
+
*/
|
|
237
|
+
interface TransactionContext {
|
|
238
|
+
readonly type: 'transaction';
|
|
239
|
+
readonly tx: Transaction;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Batch context - write-only operations.
|
|
243
|
+
*/
|
|
244
|
+
interface BatchContext {
|
|
245
|
+
readonly type: 'batch';
|
|
246
|
+
readonly batch: WriteBatch;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Union of all operation contexts.
|
|
250
|
+
*/
|
|
251
|
+
type OperationContext = TransactionContext | BatchContext;
|
|
252
|
+
/**
|
|
253
|
+
* Get the current operation context, if any.
|
|
254
|
+
* Returns undefined when not inside a transaction or batch.
|
|
255
|
+
*/
|
|
256
|
+
declare function getCurrentContext(): OperationContext | undefined;
|
|
257
|
+
/**
|
|
258
|
+
* Check if we're currently inside a transaction.
|
|
259
|
+
*/
|
|
260
|
+
declare function isInTransaction(): boolean;
|
|
261
|
+
/**
|
|
262
|
+
* Check if we're currently inside a batch.
|
|
263
|
+
*/
|
|
264
|
+
declare function isInBatch(): boolean;
|
|
265
|
+
/**
|
|
266
|
+
* Get the current transaction, if inside one.
|
|
267
|
+
* Returns undefined when not in a transaction.
|
|
268
|
+
*/
|
|
269
|
+
declare function getCurrentTransaction(): Transaction | undefined;
|
|
270
|
+
/**
|
|
271
|
+
* Get the current batch, if inside one.
|
|
272
|
+
* Returns undefined when not in a batch.
|
|
273
|
+
*/
|
|
274
|
+
declare function getCurrentBatch(): WriteBatch | undefined;
|
|
275
|
+
/**
|
|
276
|
+
* Run a function within a transaction context.
|
|
277
|
+
* @internal Used by runTransaction()
|
|
278
|
+
*/
|
|
279
|
+
declare function runWithTransaction<T>(tx: Transaction, fn: () => Promise<T>): Promise<T>;
|
|
280
|
+
/**
|
|
281
|
+
* Run a function within a batch context.
|
|
282
|
+
* @internal Used by writeBatch()
|
|
283
|
+
*/
|
|
284
|
+
declare function runWithBatch<T>(batch: WriteBatch, fn: () => Promise<T>): Promise<T>;
|
|
285
|
+
/**
|
|
286
|
+
* Type guard for transaction context.
|
|
287
|
+
*/
|
|
288
|
+
declare function isTransactionContext(ctx?: OperationContext): ctx is TransactionContext;
|
|
289
|
+
/**
|
|
290
|
+
* Type guard for batch context.
|
|
291
|
+
*/
|
|
292
|
+
declare function isBatchContext(ctx?: OperationContext): ctx is BatchContext;
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/errors.d.ts
|
|
295
|
+
/**
|
|
296
|
+
* FyreStack Custom Error Types
|
|
297
|
+
*
|
|
298
|
+
* Provides typed errors for better error handling and debugging.
|
|
299
|
+
*/
|
|
300
|
+
/**
|
|
301
|
+
* Base error class for all FyreStack errors.
|
|
302
|
+
*/
|
|
303
|
+
declare class FyreStackError extends Error {
|
|
304
|
+
readonly code: string;
|
|
305
|
+
constructor(message: string, code: string);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Error thrown when validation fails.
|
|
309
|
+
*/
|
|
310
|
+
declare class ValidationError extends FyreStackError {
|
|
311
|
+
readonly issues: ValidationIssue[];
|
|
312
|
+
constructor(message: string, issues?: ValidationIssue[]);
|
|
313
|
+
/**
|
|
314
|
+
* Create a ValidationError from Standard Schema validation issues.
|
|
315
|
+
*/
|
|
316
|
+
static fromStandardSchema(issues: readonly StandardSchemaIssue[]): ValidationError;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Validation issue structure.
|
|
320
|
+
*/
|
|
321
|
+
interface ValidationIssue {
|
|
322
|
+
/** Path to the invalid field (e.g., ['address', 'zip']) */
|
|
323
|
+
path: string[];
|
|
324
|
+
/** Human-readable error message */
|
|
325
|
+
message: string;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Standard Schema issue structure (subset of StandardSchemaV1).
|
|
329
|
+
* Compatible with the path types from @standard-schema/spec.
|
|
330
|
+
*/
|
|
331
|
+
interface StandardSchemaIssue {
|
|
332
|
+
message: string;
|
|
333
|
+
path?: ReadonlyArray<PropertyKey | {
|
|
334
|
+
key: PropertyKey;
|
|
335
|
+
}> | undefined;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Error thrown when path parameters are invalid.
|
|
339
|
+
*/
|
|
340
|
+
declare class PathParamError extends FyreStackError {
|
|
341
|
+
readonly paramName: string;
|
|
342
|
+
readonly paramValue: string;
|
|
343
|
+
constructor(paramName: string, paramValue: string, reason: string);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Error thrown when Firestore adapter is not initialized.
|
|
347
|
+
*/
|
|
348
|
+
declare class AdapterNotInitializedError extends FyreStackError {
|
|
349
|
+
constructor();
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Error thrown when a model is missing required properties.
|
|
353
|
+
*/
|
|
354
|
+
declare class ModelError extends FyreStackError {
|
|
355
|
+
constructor(message: string);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Error thrown when a document is not found.
|
|
359
|
+
*/
|
|
360
|
+
declare class NotFoundError extends FyreStackError {
|
|
361
|
+
readonly documentPath: string;
|
|
362
|
+
constructor(documentPath: string);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Error thrown when a Firestore operation fails.
|
|
366
|
+
*/
|
|
367
|
+
declare class FirestoreError extends FyreStackError {
|
|
368
|
+
readonly originalError: unknown;
|
|
369
|
+
constructor(message: string, originalError: unknown);
|
|
370
|
+
/**
|
|
371
|
+
* Wrap a Firestore error with context.
|
|
372
|
+
*/
|
|
373
|
+
static wrap(operation: string, error: unknown): FirestoreError;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Validation result type for type-safe validation handling.
|
|
377
|
+
*/
|
|
378
|
+
type ValidationResult<T> = {
|
|
379
|
+
valid: true;
|
|
380
|
+
value: T;
|
|
381
|
+
} | {
|
|
382
|
+
valid: false;
|
|
383
|
+
error: ValidationError;
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Helper to check if a ValidationResult is valid.
|
|
387
|
+
*/
|
|
388
|
+
declare function isValidResult<T>(result: ValidationResult<T>): result is {
|
|
389
|
+
valid: true;
|
|
390
|
+
value: T;
|
|
391
|
+
};
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/model.hooks.d.ts
|
|
394
|
+
/**
|
|
395
|
+
* Context passed to repository hooks during operations.
|
|
396
|
+
* Provides access to the adapter, model info, and operation details.
|
|
397
|
+
*/
|
|
398
|
+
interface RepositoryHookContext {
|
|
399
|
+
/** The Firestore adapter for accessing Firebase functionality */
|
|
400
|
+
adapter: FirestoreAdapter;
|
|
401
|
+
/** The model class being operated on */
|
|
402
|
+
modelClass: Type<unknown>;
|
|
403
|
+
/** The collection path template */
|
|
404
|
+
path: string;
|
|
405
|
+
/** The resolved path parameters */
|
|
406
|
+
params: Record<string, string>;
|
|
407
|
+
/** The document ID (if applicable) */
|
|
408
|
+
id?: string;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Context passed to model hooks during construction/validation.
|
|
412
|
+
*/
|
|
413
|
+
interface ModelHookContext {
|
|
414
|
+
/** The model class being constructed */
|
|
415
|
+
modelClass: Type<unknown>;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Hooks that can be registered for model lifecycle events.
|
|
419
|
+
*/
|
|
420
|
+
interface ModelHooks {
|
|
421
|
+
/**
|
|
422
|
+
* Called during model construction, can transform props.
|
|
423
|
+
* @param props - The properties being assigned to the model
|
|
424
|
+
* @param context - Model context
|
|
425
|
+
* @returns Transformed props
|
|
426
|
+
*/
|
|
427
|
+
onConstruct?: (props: Record<string, unknown>, context: ModelHookContext) => Record<string, unknown>;
|
|
428
|
+
/**
|
|
429
|
+
* Called during model validation.
|
|
430
|
+
* Can throw ValidationError to fail validation.
|
|
431
|
+
* @param data - The data being validated
|
|
432
|
+
* @param context - Model context
|
|
433
|
+
*/
|
|
434
|
+
onValidate?: (data: unknown, context: ModelHookContext) => void;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Hooks that can be registered for repository operations.
|
|
438
|
+
* Hooks can transform data or perform side effects.
|
|
439
|
+
*/
|
|
440
|
+
interface RepositoryHooks {
|
|
441
|
+
/**
|
|
442
|
+
* Called before save operation.
|
|
443
|
+
* Can modify the data being saved.
|
|
444
|
+
* @param data - The data to be saved
|
|
445
|
+
* @param context - Repository context with adapter access
|
|
446
|
+
* @returns Modified data (or original if unchanged)
|
|
447
|
+
*/
|
|
448
|
+
beforeSave?: (data: Record<string, unknown>, context: RepositoryHookContext) => Record<string, unknown>;
|
|
449
|
+
/**
|
|
450
|
+
* Called after save operation completes successfully.
|
|
451
|
+
* @param data - The data that was saved
|
|
452
|
+
* @param context - Repository context
|
|
453
|
+
*/
|
|
454
|
+
afterSave?: (data: Record<string, unknown>, context: RepositoryHookContext) => void;
|
|
455
|
+
/**
|
|
456
|
+
* Called before update operation.
|
|
457
|
+
* Can modify the update data (dot-notation fields).
|
|
458
|
+
* @param updates - The update data
|
|
459
|
+
* @param context - Repository context with adapter access
|
|
460
|
+
* @returns Modified updates (or original if unchanged)
|
|
461
|
+
*/
|
|
462
|
+
beforeUpdate?: (updates: Record<string, unknown>, context: RepositoryHookContext) => Record<string, unknown>;
|
|
463
|
+
/**
|
|
464
|
+
* Called after update operation completes successfully.
|
|
465
|
+
* @param updates - The update data that was applied
|
|
466
|
+
* @param context - Repository context
|
|
467
|
+
*/
|
|
468
|
+
afterUpdate?: (updates: Record<string, unknown>, context: RepositoryHookContext) => void;
|
|
469
|
+
/**
|
|
470
|
+
* Called before delete operation.
|
|
471
|
+
* Can throw to prevent deletion.
|
|
472
|
+
* @param context - Repository context
|
|
473
|
+
*/
|
|
474
|
+
beforeDelete?: (context: RepositoryHookContext) => void;
|
|
475
|
+
/**
|
|
476
|
+
* Called after delete operation completes successfully.
|
|
477
|
+
* @param context - Repository context
|
|
478
|
+
*/
|
|
479
|
+
afterDelete?: (context: RepositoryHookContext) => void;
|
|
480
|
+
/**
|
|
481
|
+
* Called after get operation, can transform the result.
|
|
482
|
+
* @param data - The fetched data (or null if not found)
|
|
483
|
+
* @param context - Repository context
|
|
484
|
+
* @returns Transformed data
|
|
485
|
+
*/
|
|
486
|
+
afterGet?: (data: Record<string, unknown> | null, context: RepositoryHookContext) => Record<string, unknown> | null;
|
|
487
|
+
/**
|
|
488
|
+
* Called after find operation, can transform results.
|
|
489
|
+
* @param data - Array of fetched documents
|
|
490
|
+
* @param context - Repository context
|
|
491
|
+
* @returns Transformed array
|
|
492
|
+
*/
|
|
493
|
+
afterFind?: (data: Record<string, unknown>[], context: RepositoryHookContext) => Record<string, unknown>[];
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Combined hooks for both model and repository lifecycle.
|
|
497
|
+
*/
|
|
498
|
+
interface FeatureHooks {
|
|
499
|
+
/** Hooks for model lifecycle events */
|
|
500
|
+
model?: ModelHooks;
|
|
501
|
+
/** Hooks for repository operations */
|
|
502
|
+
repository?: RepositoryHooks;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Merge multiple repository hooks into a single hooks object.
|
|
506
|
+
* When multiple hooks define the same method, they are chained in order.
|
|
507
|
+
*/
|
|
508
|
+
declare function mergeRepositoryHooks(...hooksList: (RepositoryHooks | undefined)[]): RepositoryHooks;
|
|
509
|
+
/**
|
|
510
|
+
* Merge multiple model hooks into a single hooks object.
|
|
511
|
+
*/
|
|
512
|
+
declare function mergeModelHooks(...hooksList: (ModelHooks | undefined)[]): ModelHooks;
|
|
513
|
+
/**
|
|
514
|
+
* Merge feature hooks (combines both model and repository hooks).
|
|
515
|
+
*/
|
|
516
|
+
declare function mergeFeatureHooks(...hooksList: (FeatureHooks | undefined)[]): FeatureHooks;
|
|
517
|
+
//#endregion
|
|
518
|
+
//#region src/model.metadata.d.ts
|
|
519
|
+
/**
|
|
520
|
+
* Symbol used to store metadata on model classes.
|
|
521
|
+
* Using a symbol prevents conflicts with user-defined properties.
|
|
522
|
+
*/
|
|
523
|
+
declare const MODEL_METADATA: unique symbol;
|
|
524
|
+
/**
|
|
525
|
+
* Model metadata containing registered feature hooks.
|
|
526
|
+
* This is stored on the model class and read by repositories.
|
|
527
|
+
*/
|
|
528
|
+
interface ModelMetadata {
|
|
529
|
+
/**
|
|
530
|
+
* Combined hooks from all registered features.
|
|
531
|
+
*/
|
|
532
|
+
hooks?: FeatureHooks;
|
|
533
|
+
/**
|
|
534
|
+
* Feature-specific configuration data.
|
|
535
|
+
* Features can store their config here for introspection.
|
|
536
|
+
*/
|
|
537
|
+
features?: Record<string, unknown>;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Get metadata from a model class.
|
|
541
|
+
*/
|
|
542
|
+
declare function getModelMetadata(ModelClass: unknown): ModelMetadata | undefined;
|
|
543
|
+
/**
|
|
544
|
+
* Get repository hooks from a model class.
|
|
545
|
+
*/
|
|
546
|
+
declare function getRepositoryHooks(ModelClass: unknown): RepositoryHooks | undefined;
|
|
547
|
+
/**
|
|
548
|
+
* Get model hooks from a model class.
|
|
549
|
+
*/
|
|
550
|
+
declare function getModelHooks(ModelClass: unknown): ModelHooks | undefined;
|
|
551
|
+
/**
|
|
552
|
+
* Check if a model has any repository hooks registered.
|
|
553
|
+
*/
|
|
554
|
+
declare function hasRepositoryHooks(ModelClass: unknown): boolean;
|
|
555
|
+
/**
|
|
556
|
+
* Check if a model has a specific feature registered.
|
|
557
|
+
*/
|
|
558
|
+
declare function hasFeature(ModelClass: unknown, featureName: string): boolean;
|
|
559
|
+
/**
|
|
560
|
+
* Get configuration for a specific feature.
|
|
561
|
+
*/
|
|
562
|
+
declare function getFeatureConfig<T>(ModelClass: unknown, featureName: string): T | undefined;
|
|
563
|
+
/**
|
|
564
|
+
* Create metadata for a feature.
|
|
565
|
+
* Used by feature functions like withTimestamps() to build metadata.
|
|
566
|
+
*
|
|
567
|
+
* @param featureName - Unique name for the feature
|
|
568
|
+
* @param config - Feature-specific configuration (for introspection)
|
|
569
|
+
* @param hooks - Hooks to register
|
|
570
|
+
* @param existingMetadata - Existing metadata to merge with
|
|
571
|
+
*/
|
|
572
|
+
declare function createFeatureMetadata(featureName: string, config: unknown, hooks: FeatureHooks, existingMetadata?: ModelMetadata): ModelMetadata;
|
|
573
|
+
/**
|
|
574
|
+
* Configuration for automatic timestamp management.
|
|
575
|
+
*/
|
|
576
|
+
interface TimestampsConfig {
|
|
577
|
+
/**
|
|
578
|
+
* Field name for creation timestamp.
|
|
579
|
+
* Set to `false` to disable.
|
|
580
|
+
* @default 'createdAt'
|
|
581
|
+
*/
|
|
582
|
+
createdAt: string | false;
|
|
583
|
+
/**
|
|
584
|
+
* Field name for last update timestamp.
|
|
585
|
+
* Set to `false` to disable.
|
|
586
|
+
* @default 'updatedAt'
|
|
587
|
+
*/
|
|
588
|
+
updatedAt: string | false;
|
|
589
|
+
/**
|
|
590
|
+
* Whether to use Firestore serverTimestamp() for accuracy.
|
|
591
|
+
* When false, uses client-side Date.
|
|
592
|
+
* @default true
|
|
593
|
+
*/
|
|
594
|
+
useServerTimestamp: boolean;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* User-provided options for configuring timestamps.
|
|
598
|
+
* All fields are optional with sensible defaults.
|
|
599
|
+
*/
|
|
600
|
+
interface TimestampsOptions {
|
|
601
|
+
/**
|
|
602
|
+
* Field name for creation timestamp, or `false` to disable.
|
|
603
|
+
* @default 'createdAt'
|
|
604
|
+
*/
|
|
605
|
+
createdAt?: string | false;
|
|
606
|
+
/**
|
|
607
|
+
* Field name for last update timestamp, or `false` to disable.
|
|
608
|
+
* @default 'updatedAt'
|
|
609
|
+
*/
|
|
610
|
+
updatedAt?: string | false;
|
|
611
|
+
/**
|
|
612
|
+
* Whether to use Firestore serverTimestamp().
|
|
613
|
+
* @default true
|
|
614
|
+
*/
|
|
615
|
+
useServerTimestamp?: boolean;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Default timestamp configuration.
|
|
619
|
+
*/
|
|
620
|
+
declare const DEFAULT_TIMESTAMPS: TimestampsConfig;
|
|
621
|
+
/**
|
|
622
|
+
* Configuration for audit trail management.
|
|
623
|
+
* Tracks which user created/modified documents.
|
|
624
|
+
*/
|
|
625
|
+
interface AuditConfig {
|
|
626
|
+
/**
|
|
627
|
+
* Field name for creator user ID.
|
|
628
|
+
* Set to `false` to disable.
|
|
629
|
+
* @default 'createdBy'
|
|
630
|
+
*/
|
|
631
|
+
createdBy: string | false;
|
|
632
|
+
/**
|
|
633
|
+
* Field name for last modifier user ID.
|
|
634
|
+
* Set to `false` to disable.
|
|
635
|
+
* @default 'updatedBy'
|
|
636
|
+
*/
|
|
637
|
+
updatedBy: string | false;
|
|
638
|
+
/**
|
|
639
|
+
* Function to get the current user ID.
|
|
640
|
+
* Must be provided when using audit feature.
|
|
641
|
+
*/
|
|
642
|
+
getCurrentUserId: () => string | null;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* User-provided options for configuring audit trail.
|
|
646
|
+
*/
|
|
647
|
+
interface AuditOptions {
|
|
648
|
+
createdBy?: string | false;
|
|
649
|
+
updatedBy?: string | false;
|
|
650
|
+
getCurrentUserId: () => string | null;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Default audit configuration.
|
|
654
|
+
*/
|
|
655
|
+
declare const DEFAULT_AUDIT: Omit<AuditConfig, 'getCurrentUserId'>;
|
|
656
|
+
/**
|
|
657
|
+
* Configuration for status field management including soft-delete.
|
|
658
|
+
*/
|
|
659
|
+
interface StatusConfig {
|
|
660
|
+
/**
|
|
661
|
+
* Field name for status.
|
|
662
|
+
* @default 'status'
|
|
663
|
+
*/
|
|
664
|
+
field: string;
|
|
665
|
+
/**
|
|
666
|
+
* Available status values.
|
|
667
|
+
* @default ['active', 'inactive', 'deleted']
|
|
668
|
+
*/
|
|
669
|
+
values: readonly string[];
|
|
670
|
+
/**
|
|
671
|
+
* Default status for new documents.
|
|
672
|
+
* @default 'active'
|
|
673
|
+
*/
|
|
674
|
+
defaultValue: string;
|
|
675
|
+
/**
|
|
676
|
+
* Status value that indicates soft-deletion.
|
|
677
|
+
* When set, delete operations will set this status instead of hard-deleting.
|
|
678
|
+
* @default 'deleted'
|
|
679
|
+
*/
|
|
680
|
+
deletedValue: string | false;
|
|
681
|
+
/**
|
|
682
|
+
* Field name for deletion timestamp (when soft-delete is enabled).
|
|
683
|
+
* @default 'deletedAt'
|
|
684
|
+
*/
|
|
685
|
+
deletedAt: string | false;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* User-provided options for configuring status.
|
|
689
|
+
*/
|
|
690
|
+
interface StatusOptions {
|
|
691
|
+
field?: string;
|
|
692
|
+
values?: readonly string[];
|
|
693
|
+
defaultValue?: string;
|
|
694
|
+
deletedValue?: string | false;
|
|
695
|
+
deletedAt?: string | false;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Default status configuration.
|
|
699
|
+
*/
|
|
700
|
+
declare const DEFAULT_STATUS: StatusConfig;
|
|
701
|
+
/**
|
|
702
|
+
* Check if a model has timestamps feature.
|
|
703
|
+
*/
|
|
704
|
+
declare function hasTimestamps(ModelClass: unknown): boolean;
|
|
705
|
+
/**
|
|
706
|
+
* Get timestamps configuration from a model class.
|
|
707
|
+
*/
|
|
708
|
+
declare function getTimestampsConfig(ModelClass: unknown): TimestampsConfig | undefined;
|
|
709
|
+
/**
|
|
710
|
+
* Check if a model has audit feature.
|
|
711
|
+
*/
|
|
712
|
+
declare function hasAudit(ModelClass: unknown): boolean;
|
|
713
|
+
/**
|
|
714
|
+
* Get audit configuration from a model class.
|
|
715
|
+
*/
|
|
716
|
+
declare function getAuditConfig(ModelClass: unknown): AuditConfig | undefined;
|
|
717
|
+
/**
|
|
718
|
+
* Check if a model has status feature.
|
|
719
|
+
*/
|
|
720
|
+
declare function hasStatus(ModelClass: unknown): boolean;
|
|
721
|
+
/**
|
|
722
|
+
* Get status configuration from a model class.
|
|
723
|
+
*/
|
|
724
|
+
declare function getStatusConfig(ModelClass: unknown): StatusConfig | undefined;
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region src/model.types.d.ts
|
|
727
|
+
/**
|
|
728
|
+
* Symbol for storing the schema on model instances (internal use).
|
|
729
|
+
*/
|
|
730
|
+
declare const MODEL_SCHEMA: unique symbol;
|
|
731
|
+
/**
|
|
732
|
+
* Infer the instance type from a Model class.
|
|
733
|
+
* @example
|
|
734
|
+
* const UserModel = model(withSchema(UserSchema));
|
|
735
|
+
* type User = InferModel<typeof UserModel>;
|
|
736
|
+
*/
|
|
737
|
+
type InferModel<T extends Type<any>> = InstanceType<T>;
|
|
738
|
+
type MethodsDictionary = Record<string, Function>;
|
|
739
|
+
type InnerModel<Schema extends StandardSchemaV1 = StandardSchemaV1, Props extends object = object, Methods extends MethodsDictionary = MethodsDictionary, Metadata extends ModelMetadata | undefined = ModelMetadata | undefined> = {
|
|
740
|
+
schema: Schema;
|
|
741
|
+
props: Props;
|
|
742
|
+
methods: Methods;
|
|
743
|
+
_metadata?: Metadata;
|
|
744
|
+
};
|
|
745
|
+
type ModelFeatureResult = {
|
|
746
|
+
schema: StandardSchemaV1;
|
|
747
|
+
props: object;
|
|
748
|
+
methods: MethodsDictionary;
|
|
749
|
+
_metadata?: ModelMetadata;
|
|
750
|
+
};
|
|
751
|
+
type ModelFeature<Input extends ModelFeatureResult = ModelFeatureResult, Output extends ModelFeatureResult = ModelFeatureResult> = (store: InnerModel<Input['schema'], Input['props'], Input['methods'], Input['_metadata']>) => InnerModel<Output['schema'], Output['props'], Output['methods'], Output['_metadata']>;
|
|
752
|
+
type EmptyFeatureResult = ModelFeatureResult & {
|
|
753
|
+
props: {};
|
|
754
|
+
methods: {};
|
|
755
|
+
};
|
|
756
|
+
/**
|
|
757
|
+
* Interface for model instances with validation methods.
|
|
758
|
+
*/
|
|
759
|
+
interface ModelInstance<T = unknown> {
|
|
760
|
+
/**
|
|
761
|
+
* Validate the current model data.
|
|
762
|
+
* @returns ValidationResult with either the validated value or error
|
|
763
|
+
*/
|
|
764
|
+
validate(): ValidationResult<T>;
|
|
765
|
+
/**
|
|
766
|
+
* Check if the model data is valid.
|
|
767
|
+
* @returns true if valid, false otherwise
|
|
768
|
+
*/
|
|
769
|
+
isValid(): boolean;
|
|
770
|
+
/**
|
|
771
|
+
* Convert model to a plain object (for Firestore writes).
|
|
772
|
+
* Excludes methods, keeps only data properties.
|
|
773
|
+
*/
|
|
774
|
+
toObject(): T;
|
|
775
|
+
}
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region src/model.d.ts
|
|
778
|
+
type ModelMembers<FeatureResult extends ModelFeatureResult> = Prettify<OmitPrivate<FeatureResult['props'] & FeatureResult['methods']>>;
|
|
779
|
+
declare function model<F1 extends ModelFeatureResult>(f1: ModelFeature<EmptyFeatureResult, F1>): Type<ModelMembers<F1>>;
|
|
780
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>): Type<ModelMembers<R>>;
|
|
781
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>): Type<ModelMembers<R>>;
|
|
782
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>): Type<ModelMembers<R>>;
|
|
783
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, F5 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>, f5: ModelFeature<F1 & F2 & F3 & F4, F5>): Type<ModelMembers<R>>;
|
|
784
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, F5 extends ModelFeatureResult, F6 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>, f5: ModelFeature<F1 & F2 & F3 & F4, F5>, f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>): Type<ModelMembers<R>>;
|
|
785
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, F5 extends ModelFeatureResult, F6 extends ModelFeatureResult, F7 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>, f5: ModelFeature<F1 & F2 & F3 & F4, F5>, f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>, f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>): Type<ModelMembers<R>>;
|
|
786
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, F5 extends ModelFeatureResult, F6 extends ModelFeatureResult, F7 extends ModelFeatureResult, F8 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>, f5: ModelFeature<F1 & F2 & F3 & F4, F5>, f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>, f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>, f8: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7, F8>): Type<ModelMembers<R>>;
|
|
787
|
+
declare function model<F1 extends ModelFeatureResult, F2 extends ModelFeatureResult, F3 extends ModelFeatureResult, F4 extends ModelFeatureResult, F5 extends ModelFeatureResult, F6 extends ModelFeatureResult, F7 extends ModelFeatureResult, F8 extends ModelFeatureResult, F9 extends ModelFeatureResult, R extends ModelFeatureResult = F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8 & F9>(f1: ModelFeature<EmptyFeatureResult, F1>, f2: ModelFeature<{} & F1, F2>, f3: ModelFeature<F1 & F2, F3>, f4: ModelFeature<F1 & F2 & F3, F4>, f5: ModelFeature<F1 & F2 & F3 & F4, F5>, f6: ModelFeature<F1 & F2 & F3 & F4 & F5, F6>, f7: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6, F7>, f8: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7, F8>, f9: ModelFeature<F1 & F2 & F3 & F4 & F5 & F6 & F7 & F8, F9>): Type<ModelMembers<R>>;
|
|
788
|
+
//#endregion
|
|
789
|
+
//#region src/model.with-schema.d.ts
|
|
790
|
+
declare function withSchema<S extends StandardSchemaV1>(schema: S): ModelFeature<EmptyFeatureResult, {
|
|
791
|
+
schema: S;
|
|
792
|
+
props: StandardSchemaV1.InferOutput<S> & object;
|
|
793
|
+
methods: {};
|
|
794
|
+
}>;
|
|
795
|
+
//#endregion
|
|
796
|
+
//#region src/model.with-timestamps.d.ts
|
|
797
|
+
/**
|
|
798
|
+
* Firestore Timestamp interface - matches both firebase/firestore and firebase-admin/firestore.
|
|
799
|
+
* This allows strict typing without coupling to a specific Firebase SDK.
|
|
800
|
+
*/
|
|
801
|
+
interface FirestoreTimestamp {
|
|
802
|
+
readonly seconds: number;
|
|
803
|
+
readonly nanoseconds: number;
|
|
804
|
+
toDate(): Date;
|
|
805
|
+
toMillis(): number;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Possible values for a timestamp field on a model instance:
|
|
809
|
+
* - `Date` - after conversion from Firestore
|
|
810
|
+
* - `FirestoreTimestamp` - raw Firestore Timestamp before conversion
|
|
811
|
+
* - `undefined` - if not yet set
|
|
812
|
+
*/
|
|
813
|
+
type TimestampValue = Date | FirestoreTimestamp | undefined;
|
|
814
|
+
/**
|
|
815
|
+
* Timestamp props type - added to model by withTimestamps.
|
|
816
|
+
*/
|
|
817
|
+
type TimestampProps<CreatedField extends string | false = 'createdAt', UpdatedField extends string | false = 'updatedAt'> = (CreatedField extends string ? { [K in CreatedField]?: TimestampValue } : object) & (UpdatedField extends string ? { [K in UpdatedField]?: TimestampValue } : object);
|
|
818
|
+
/**
|
|
819
|
+
* Output type for withTimestamps feature - includes metadata
|
|
820
|
+
*/
|
|
821
|
+
type WithTimestampsOutput<Input extends ModelFeatureResult> = {
|
|
822
|
+
schema: Input['schema'];
|
|
823
|
+
props: Input['props'] & TimestampProps;
|
|
824
|
+
methods: Input['methods'];
|
|
825
|
+
_metadata: ModelMetadata;
|
|
826
|
+
};
|
|
827
|
+
/**
|
|
828
|
+
* Add automatic timestamp management to a model.
|
|
829
|
+
*
|
|
830
|
+
* This feature registers hooks that:
|
|
831
|
+
* - Set `createdAt` on save (if not already set)
|
|
832
|
+
* - Set `updatedAt` on save and update
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* ```typescript
|
|
836
|
+
* // Basic usage with defaults (createdAt, updatedAt)
|
|
837
|
+
* const UserModel = model(
|
|
838
|
+
* withSchema(UserSchema),
|
|
839
|
+
* withTimestamps(),
|
|
840
|
+
* );
|
|
841
|
+
*
|
|
842
|
+
* // Custom field names
|
|
843
|
+
* const PostModel = model(
|
|
844
|
+
* withSchema(PostSchema),
|
|
845
|
+
* withTimestamps({ createdAt: 'publishedAt', updatedAt: 'modifiedAt' }),
|
|
846
|
+
* );
|
|
847
|
+
*
|
|
848
|
+
* // Disable one field
|
|
849
|
+
* const LogModel = model(
|
|
850
|
+
* withSchema(LogSchema),
|
|
851
|
+
* withTimestamps({ updatedAt: false }), // Only track creation
|
|
852
|
+
* );
|
|
853
|
+
*
|
|
854
|
+
* // Use client-side timestamps (for offline support)
|
|
855
|
+
* const OfflineModel = model(
|
|
856
|
+
* withSchema(OfflineSchema),
|
|
857
|
+
* withTimestamps({ useServerTimestamp: false }),
|
|
858
|
+
* );
|
|
859
|
+
* ```
|
|
860
|
+
*
|
|
861
|
+
* @param options - Optional configuration for field names and behavior
|
|
862
|
+
*/
|
|
863
|
+
declare function withTimestamps<Input extends ModelFeatureResult>(options?: TimestampsOptions): ModelFeature<Input, WithTimestampsOutput<Input>>;
|
|
864
|
+
//#endregion
|
|
865
|
+
//#region src/repository.types.d.ts
|
|
866
|
+
type RepositoryMethodsDictionary = Record<string, Function>;
|
|
867
|
+
type InnerRepository<Model = unknown, Path extends string = string, Methods extends RepositoryMethodsDictionary = RepositoryMethodsDictionary> = {
|
|
868
|
+
model: Type<Model>;
|
|
869
|
+
path: Path;
|
|
870
|
+
methods: Methods;
|
|
871
|
+
getCollection(params: ExtractPathParams<Path>): CollectionReference<Model>;
|
|
872
|
+
getDocument(params: ExtractPathParams<Path>, id: string): DocumentReference<Model>;
|
|
873
|
+
};
|
|
874
|
+
type RepositoryFeatureResult<Model = unknown, Path extends string = string, Methods extends RepositoryMethodsDictionary = RepositoryMethodsDictionary> = {
|
|
875
|
+
model: Type<Model>;
|
|
876
|
+
path: Path;
|
|
877
|
+
methods: Methods;
|
|
878
|
+
};
|
|
879
|
+
type RepositoryFeature<Input extends RepositoryFeatureResult = RepositoryFeatureResult, Output extends RepositoryFeatureResult = RepositoryFeatureResult> = (repo: InnerRepository<Input['model'], Input['path'], Input['methods']>) => Output['methods'];
|
|
880
|
+
type RepositoryConfig<Model, Path extends string> = {
|
|
881
|
+
path: Path;
|
|
882
|
+
model: Type<Model>;
|
|
883
|
+
};
|
|
884
|
+
/**
|
|
885
|
+
* Base repository methods available on all repositories.
|
|
886
|
+
*
|
|
887
|
+
* Transaction/batch context is automatically detected from AsyncContext -
|
|
888
|
+
* no need to pass context explicitly.
|
|
889
|
+
*/
|
|
890
|
+
type BaseRepositoryMethods<Model, Path extends string> = {
|
|
891
|
+
/**
|
|
892
|
+
* Get a single document by ID.
|
|
893
|
+
* Automatically uses transaction context if called within runTransaction().
|
|
894
|
+
*
|
|
895
|
+
* @param params - Path parameters for nested collections
|
|
896
|
+
* @param id - Document ID
|
|
897
|
+
*/
|
|
898
|
+
get(params: ExtractPathParams<Path>, id: string): Promise<Model | null>;
|
|
899
|
+
/**
|
|
900
|
+
* Find documents matching a query.
|
|
901
|
+
* Automatically uses transaction context if called within runTransaction().
|
|
902
|
+
*
|
|
903
|
+
* @param params - Path parameters for nested collections
|
|
904
|
+
* @param queryFn - Optional query builder function
|
|
905
|
+
*/
|
|
906
|
+
find(params: ExtractPathParams<Path>, queryFn?: QueryFn<Model>): Promise<Model[]>;
|
|
907
|
+
/**
|
|
908
|
+
* Save a model (create or overwrite entire document).
|
|
909
|
+
* Automatically uses transaction/batch context if called within runTransaction() or writeBatch().
|
|
910
|
+
*
|
|
911
|
+
* @param params - Path parameters for nested collections
|
|
912
|
+
* @param model - Model instance to save
|
|
913
|
+
*/
|
|
914
|
+
save(params: ExtractPathParams<Path>, model: Model): Promise<void>;
|
|
915
|
+
/**
|
|
916
|
+
* Update specific fields using Firestore dot-notation.
|
|
917
|
+
* Automatically uses transaction/batch context if called within runTransaction() or writeBatch().
|
|
918
|
+
*
|
|
919
|
+
* @param params - Path parameters for nested collections
|
|
920
|
+
* @param modelOrId - Model instance or document ID
|
|
921
|
+
* @param updates - Fields to update (supports dot-notation)
|
|
922
|
+
*/
|
|
923
|
+
update(params: ExtractPathParams<Path>, modelOrId: Model | string, updates: FirestoreUpdate<Model>): Promise<void>;
|
|
924
|
+
/**
|
|
925
|
+
* Delete a document.
|
|
926
|
+
* Automatically uses transaction/batch context if called within runTransaction() or writeBatch().
|
|
927
|
+
*
|
|
928
|
+
* @param params - Path parameters for nested collections
|
|
929
|
+
* @param modelOrId - Model instance or document ID
|
|
930
|
+
*/
|
|
931
|
+
delete(params: ExtractPathParams<Path>, modelOrId: Model | string): Promise<void>;
|
|
932
|
+
};
|
|
933
|
+
/**
|
|
934
|
+
* Primitive types that should not be recursed into
|
|
935
|
+
*/
|
|
936
|
+
type Primitive = string | number | boolean | bigint | symbol | null | undefined | Date;
|
|
937
|
+
/**
|
|
938
|
+
* Generate all valid dot-notation paths from a type.
|
|
939
|
+
* Handles nested objects and optional properties.
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* type User = { name: string; address?: { city: string; zip: number } };
|
|
943
|
+
* type Paths = DotPaths<User>; // 'name' | 'address' | 'address.city' | 'address.zip'
|
|
944
|
+
*/
|
|
945
|
+
type DotPaths<T, Prefix extends string = ''> = T extends Primitive ? never : T extends any[] ? Prefix extends '' ? never : never : T extends object ? { [K in keyof T & string]: `${Prefix}${K}` | (NonNullable<T[K]> extends Primitive ? never : NonNullable<T[K]> extends any[] ? never : DotPaths<NonNullable<T[K]>, `${Prefix}${K}.`>) }[keyof T & string] : never;
|
|
946
|
+
/**
|
|
947
|
+
* Get the value type at a specific dot-notation path.
|
|
948
|
+
*
|
|
949
|
+
* @example
|
|
950
|
+
* type User = { address: { zip: number } };
|
|
951
|
+
* type ZipType = PathValue<User, 'address.zip'>; // number
|
|
952
|
+
*/
|
|
953
|
+
type PathValue<T, P$1 extends string> = P$1 extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<NonNullable<T[K]>, Rest> : never : P$1 extends keyof T ? T[P$1] : never;
|
|
954
|
+
/**
|
|
955
|
+
* Firestore-style update object where keys are dot-notation paths
|
|
956
|
+
* and values are type-checked against the path's type.
|
|
957
|
+
*
|
|
958
|
+
* @example
|
|
959
|
+
* type User = { name: string; address: { zip: number } };
|
|
960
|
+
* const update: FirestoreUpdate<User> = {
|
|
961
|
+
* name: 'Bob', // ✓ valid
|
|
962
|
+
* 'address.zip': 12345, // ✓ valid
|
|
963
|
+
* 'address.zip': 'bad', // ✗ type error
|
|
964
|
+
* };
|
|
965
|
+
*/
|
|
966
|
+
type FirestoreUpdate<T> = { [P in DotPaths<T>]?: PathValue<T, P> };
|
|
967
|
+
/**
|
|
968
|
+
* Extract path parameters from a Firestore path string.
|
|
969
|
+
*
|
|
970
|
+
* @example
|
|
971
|
+
* type Params = ExtractPathParams<'organizations/{organization}/users/{user}'>;
|
|
972
|
+
* // { organization: string; user: string }
|
|
973
|
+
*/
|
|
974
|
+
type ExtractPathParams<T extends string> = string extends T ? Record<string, string> : T extends `${string}{${infer Param}}${infer Rest}` ? { [K in Param]: string } & ExtractPathParams<Rest> : {};
|
|
975
|
+
/**
|
|
976
|
+
* Check if path params are required (not an empty object)
|
|
977
|
+
*/
|
|
978
|
+
type HasPathParams<T extends string> = keyof ExtractPathParams<T> extends never ? false : true;
|
|
979
|
+
/**
|
|
980
|
+
* Type-safe query builder interface.
|
|
981
|
+
* Wraps Firestore query methods with typed field names.
|
|
982
|
+
*/
|
|
983
|
+
interface TypedQueryBuilder<T> {
|
|
984
|
+
where<K$1 extends DotPaths<T>>(field: K$1, op: WhereFilterOp, value: PathValue<T, K$1>): TypedQueryBuilder<T>;
|
|
985
|
+
orderBy(field: DotPaths<T>, direction?: OrderByDirection): TypedQueryBuilder<T>;
|
|
986
|
+
limit(count: number): TypedQueryBuilder<T>;
|
|
987
|
+
startAt(...values: unknown[]): TypedQueryBuilder<T>;
|
|
988
|
+
startAfter(...values: unknown[]): TypedQueryBuilder<T>;
|
|
989
|
+
endAt(...values: unknown[]): TypedQueryBuilder<T>;
|
|
990
|
+
endBefore(...values: unknown[]): TypedQueryBuilder<T>;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Query function type for find() method
|
|
994
|
+
*/
|
|
995
|
+
type QueryFn<T> = (query: TypedQueryBuilder<T>) => TypedQueryBuilder<T>;
|
|
996
|
+
//#endregion
|
|
997
|
+
//#region src/repository.d.ts
|
|
998
|
+
declare function repository<Model, Path extends string>(config: RepositoryConfig<Model, Path>): Type<BaseRepositoryMethods<Model, Path>>;
|
|
999
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods>>;
|
|
1000
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods>>;
|
|
1001
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods>>;
|
|
1002
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods>>;
|
|
1003
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary, F5Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>, f5: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F5Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods>>;
|
|
1004
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary, F5Methods extends RepositoryMethodsDictionary, F6Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>, f5: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F5Methods>>, f6: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F6Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods & F6Methods>>;
|
|
1005
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary, F5Methods extends RepositoryMethodsDictionary, F6Methods extends RepositoryMethodsDictionary, F7Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>, f5: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F5Methods>>, f6: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F6Methods>>, f7: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F7Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods & F6Methods & F7Methods>>;
|
|
1006
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary, F5Methods extends RepositoryMethodsDictionary, F6Methods extends RepositoryMethodsDictionary, F7Methods extends RepositoryMethodsDictionary, F8Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>, f5: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F5Methods>>, f6: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F6Methods>>, f7: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F7Methods>>, f8: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F8Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods & F6Methods & F7Methods & F8Methods>>;
|
|
1007
|
+
declare function repository<Model, Path extends string, F1Methods extends RepositoryMethodsDictionary, F2Methods extends RepositoryMethodsDictionary, F3Methods extends RepositoryMethodsDictionary, F4Methods extends RepositoryMethodsDictionary, F5Methods extends RepositoryMethodsDictionary, F6Methods extends RepositoryMethodsDictionary, F7Methods extends RepositoryMethodsDictionary, F8Methods extends RepositoryMethodsDictionary, F9Methods extends RepositoryMethodsDictionary>(config: RepositoryConfig<Model, Path>, f1: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F1Methods>>, f2: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F2Methods>>, f3: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F3Methods>>, f4: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F4Methods>>, f5: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F5Methods>>, f6: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F6Methods>>, f7: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F7Methods>>, f8: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F8Methods>>, f9: RepositoryFeature<RepositoryFeatureResult<Model, Path>, RepositoryFeatureResult<Model, Path, F9Methods>>): Type<Prettify<BaseRepositoryMethods<Model, Path> & F1Methods & F2Methods & F3Methods & F4Methods & F5Methods & F6Methods & F7Methods & F8Methods & F9Methods>>;
|
|
1008
|
+
//#endregion
|
|
1009
|
+
//#region src/repository.with-methods.d.ts
|
|
1010
|
+
/**
|
|
1011
|
+
* Add custom methods to a repository
|
|
1012
|
+
*/
|
|
1013
|
+
declare function withMethods<Model, Path extends string, BaseMethods extends RepositoryMethodsDictionary, NewMethods extends RepositoryMethodsDictionary>(methodsFactory: (repo: InnerRepository<Model, Path, BaseMethods>) => NewMethods): RepositoryFeature<RepositoryFeatureResult<Model, Path, BaseMethods>, RepositoryFeatureResult<Model, Path, BaseMethods & NewMethods>>;
|
|
1014
|
+
//#endregion
|
|
1015
|
+
//#region src/transaction.d.ts
|
|
1016
|
+
/**
|
|
1017
|
+
* Run operations within a Firestore transaction.
|
|
1018
|
+
*
|
|
1019
|
+
* Transactions provide:
|
|
1020
|
+
* - Atomic reads and writes across multiple repositories
|
|
1021
|
+
* - Automatic retry on contention (up to maxAttempts)
|
|
1022
|
+
* - Consistent view of data (all reads see same snapshot)
|
|
1023
|
+
* - All-or-nothing semantics (all writes succeed or all fail)
|
|
1024
|
+
*
|
|
1025
|
+
* The transaction context is **automatically propagated** to all repository
|
|
1026
|
+
* methods called within the transaction function - no need to pass context explicitly.
|
|
1027
|
+
*
|
|
1028
|
+
* @example
|
|
1029
|
+
* ```typescript
|
|
1030
|
+
* // Transfer funds between accounts atomically
|
|
1031
|
+
* const result = await runTransaction(async () => {
|
|
1032
|
+
* const fromAccount = await AccountRepo.get({}, fromId);
|
|
1033
|
+
* const toAccount = await AccountRepo.get({}, toId);
|
|
1034
|
+
*
|
|
1035
|
+
* if (!fromAccount || !toAccount) throw new Error('Account not found');
|
|
1036
|
+
* if (fromAccount.balance < amount) throw new Error('Insufficient funds');
|
|
1037
|
+
*
|
|
1038
|
+
* await AccountRepo.update({}, fromId, {
|
|
1039
|
+
* balance: fromAccount.balance - amount
|
|
1040
|
+
* });
|
|
1041
|
+
*
|
|
1042
|
+
* await AccountRepo.update({}, toId, {
|
|
1043
|
+
* balance: toAccount.balance + amount
|
|
1044
|
+
* });
|
|
1045
|
+
*
|
|
1046
|
+
* return { newBalance: fromAccount.balance - amount };
|
|
1047
|
+
* });
|
|
1048
|
+
* ```
|
|
1049
|
+
*
|
|
1050
|
+
* @example
|
|
1051
|
+
* ```typescript
|
|
1052
|
+
* // Cross-repository transaction
|
|
1053
|
+
* await runTransaction(async () => {
|
|
1054
|
+
* const order = await OrderRepo.get({}, orderId);
|
|
1055
|
+
* const user = await UserRepo.get({}, order.userId);
|
|
1056
|
+
*
|
|
1057
|
+
* await OrderRepo.update({}, orderId, { status: 'paid' });
|
|
1058
|
+
* await UserRepo.update({}, user.id, {
|
|
1059
|
+
* balance: user.balance - order.total
|
|
1060
|
+
* });
|
|
1061
|
+
* });
|
|
1062
|
+
* ```
|
|
1063
|
+
*
|
|
1064
|
+
* @param fn - Async function to run within the transaction
|
|
1065
|
+
* @param options - Transaction options (maxAttempts, etc.)
|
|
1066
|
+
* @returns Result of the transaction function
|
|
1067
|
+
*/
|
|
1068
|
+
declare function runTransaction<T>(fn: () => Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
1069
|
+
//#endregion
|
|
1070
|
+
export { AdapterNotInitializedError, AuditConfig, AuditOptions, BaseRepositoryMethods, BatchContext, CollectionReference, DEFAULT_AUDIT, DEFAULT_STATUS, DEFAULT_TIMESTAMPS, DocumentReference, DocumentSnapshot, DotPaths, EmptyFeatureResult, ExtractPathParams, FeatureHooks, FirestoreAdapter, FirestoreError, FirestoreTimestamp, FirestoreUpdate, FyreStackError, HasPathParams, InferModel, InnerModel, InnerRepository, MAX_BATCH_SIZE, MODEL_METADATA, MODEL_SCHEMA, MethodsDictionary, ModelError, ModelFeature, ModelFeatureResult, ModelHookContext, ModelHooks, ModelInstance, ModelMetadata, NotFoundError, OperationContext, OrderByDirection, PathParamError, PathValue, QueryFn, QueryReference, QuerySnapshot, RepositoryConfig, RepositoryFeature, RepositoryFeatureResult, RepositoryHookContext, RepositoryHooks, RepositoryMethodsDictionary, ServerTimestampSentinel, StatusConfig, StatusOptions, TimestampProps, TimestampValue, TimestampsConfig, TimestampsOptions, Transaction, TransactionContext, TransactionOptions, TypedQueryBuilder, ValidationError, ValidationIssue, ValidationResult, WhereFilterOp, WriteBatch, _resetFirestoreAdapter, createFeatureMetadata, getAuditConfig, getCurrentBatch, getCurrentContext, getCurrentTransaction, getFeatureConfig, getFirestoreAdapter, getModelHooks, getModelMetadata, getRepositoryHooks, getStatusConfig, getTimestampsConfig, hasAudit, hasFeature, hasRepositoryHooks, hasStatus, hasTimestamps, isBatchContext, isInBatch, isInTransaction, isServerTimestamp, isTransactionContext, isValidResult, mergeFeatureHooks, mergeModelHooks, mergeRepositoryHooks, model, repository, runTransaction, runWithBatch, runWithTransaction, setFirestoreAdapter, withMethods, withSchema, withTimestamps, writeBatch, writeChunkedBatch };
|
|
1071
|
+
//# sourceMappingURL=index.d.cts.map
|