@rebasepro/server-mongo 0.11.1-canary.gfd39654 → 0.12.0
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.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","names":[],"sources":["../src/connection.ts","../src/db/MongoConditionBuilder.ts","../src/db/MongoDataService.ts","../src/services/MongoRealtimeService.ts","../src/services/MongoHistoryService.ts","../src/services/MongoDriver.ts","../src/factory.ts","../src/auth/services.ts","../src/MongoBootstrapper.ts"],"sourcesContent":["/**\n * MongoDB Connection\n *\n * Wraps MongoDB connection to implement the DatabaseConnection interface.\n */\n\nimport { Db, MongoClient } from \"mongodb\";\nimport { DatabaseConnection } from \"@rebasepro/types\";\n\n/**\n * MongoDB database connection wrapper that implements DatabaseConnection interface.\n */\nexport class MongoDBConnection implements DatabaseConnection {\n readonly type = \"mongodb\";\n\n constructor(\n public readonly db: Db,\n public readonly client: MongoClient\n ) { }\n\n get isConnected(): boolean {\n // MongoClient doesn't have a direct isConnected property in v6+\n // We check if the client topology is connected\n try {\n const clientInternal = this.client as unknown as Record<string, { isConnected?: () => boolean } | undefined>;\n return clientInternal.topology?.isConnected?.() ?? false;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n await this.client.close();\n }\n}\n\n/**\n * Create a MongoDB database connection from a connection string.\n *\n * @param connectionString - MongoDB connection string (e.g., mongodb://localhost:27017)\n * @param databaseName - Name of the database to use\n * @returns Promise resolving to MongoDBConnection\n *\n * @example\n * ```typescript\n * const connection = await createMongoDBConnection(\n * \"mongodb://localhost:27017\",\n * \"my_database\"\n * );\n * ```\n */\nexport async function createMongoDBConnection(\n connectionString: string,\n databaseName: string\n): Promise<MongoDBConnection> {\n const client = new MongoClient(connectionString);\n await client.connect();\n const db = client.db(databaseName);\n return new MongoDBConnection(db, client);\n}\n","/**\n * MongoDB Condition Builder\n *\n * Translates Rebase filter conditions to MongoDB query operators.\n */\n\nimport { FilterValues, WhereFilterOp } from \"@rebasepro/types\";\nimport { Filter, Document } from \"mongodb\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * Mapping from Rebase filter operators to MongoDB query operators\n */\nconst REBASE_TO_MONGO_OP: Partial<Record<WhereFilterOp, string>> = {\n \"<\": \"$lt\",\n \"<=\": \"$lte\",\n \"==\": \"$eq\",\n \"!=\": \"$ne\",\n \">=\": \"$gte\",\n \">\": \"$gt\",\n \"array-contains\": \"$elemMatch\",\n \"array-contains-any\": \"$in\",\n \"in\": \"$in\",\n \"not-in\": \"$nin\"\n};\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Translate a SQL LIKE/ILIKE pattern into an anchored regular expression.\n * `%` matches any sequence of characters, `_` matches a single character;\n * every other character is matched literally.\n */\nfunction likePatternToRegExp(pattern: string, caseInsensitive: boolean): RegExp {\n let body = \"\";\n for (const ch of String(pattern)) {\n if (ch === \"%\") body += \".*\";\n else if (ch === \"_\") body += \".\";\n else body += escapeRegExp(ch);\n }\n return new RegExp(`^${body}$`, caseInsensitive ? \"i\" : \"\");\n}\n\n/**\n * MongoDB Condition Builder\n *\n * Provides static methods to translate Rebase filter conditions\n * to MongoDB query filters.\n */\nexport class MongoConditionBuilder {\n /**\n * Build MongoDB filter conditions from Rebase FilterValues\n *\n * @param filter - Rebase filter values\n * @returns Array of MongoDB filter objects\n */\n static buildFilterConditions<M extends Record<string, any>>(\n filter: FilterValues<Extract<keyof M, string>>\n ): Filter<Document>[] {\n if (!filter) return [];\n\n const conditions: Filter<Document>[] = [];\n\n for (const [field, filterParam] of Object.entries(filter)) {\n if (!filterParam) continue;\n\n const [op, value] = filterParam as [WhereFilterOp, any];\n\n // Null-testing operators ignore their value.\n if (op === \"is-null\") {\n conditions.push({ [field]: { $eq: null } });\n continue;\n }\n if (op === \"is-not-null\") {\n conditions.push({ [field]: { $ne: null } });\n continue;\n }\n\n // Pattern matching → regular expressions.\n if (op === \"like\" || op === \"ilike\" || op === \"not-like\" || op === \"not-ilike\") {\n const caseInsensitive = op === \"ilike\" || op === \"not-ilike\";\n const regex = likePatternToRegExp(value, caseInsensitive);\n const negated = op === \"not-like\" || op === \"not-ilike\";\n conditions.push({\n [field]: negated ? { $not: regex } : { $regex: regex }\n });\n continue;\n }\n\n const mongoOp = REBASE_TO_MONGO_OP[op];\n\n if (!mongoOp) {\n logger.warn(`Unsupported filter operator: ${op}`);\n continue;\n }\n\n // Handle array-contains specially\n if (op === \"array-contains\") {\n conditions.push({\n [field]: { $elemMatch: { $eq: value } }\n });\n } else {\n conditions.push({\n [field]: { [mongoOp]: value }\n });\n }\n }\n\n return conditions;\n }\n\n /**\n * Build search conditions for text search\n *\n * @param searchString - Text to search for\n * @param properties - Properties to search in\n * @returns Array of MongoDB filter objects for text search\n */\n static buildSearchConditions(\n searchString: string,\n properties: Record<string, any>\n ): Filter<Document>[] {\n if (!searchString) return [];\n\n // Build regex conditions for each searchable string property\n const orConditions: Filter<Document>[] = [];\n const escapedSearch = escapeRegExp(searchString);\n const searchRegex = new RegExp(escapedSearch, \"i\");\n\n for (const [key, prop] of Object.entries(properties)) {\n // Only search in string-type properties\n if (prop?.dataType === \"string\" || typeof prop === \"string\") {\n orConditions.push({\n [key]: { $regex: searchRegex }\n });\n }\n }\n\n // If no properties to search, use MongoDB text search\n if (orConditions.length === 0) {\n return [{ $text: { $search: searchString } }];\n }\n\n return orConditions;\n }\n\n /**\n * Combine multiple conditions with AND operator\n *\n * @param conditions - Array of filter conditions\n * @returns Combined filter or undefined if empty\n */\n static combineConditionsWithAnd(conditions: Filter<Document>[]): Filter<Document> | undefined {\n if (conditions.length === 0) return undefined;\n if (conditions.length === 1) return conditions[0];\n return { $and: conditions };\n }\n\n /**\n * Combine multiple conditions with OR operator\n *\n * @param conditions - Array of filter conditions\n * @returns Combined filter or undefined if empty\n */\n static combineConditionsWithOr(conditions: Filter<Document>[]): Filter<Document> | undefined {\n if (conditions.length === 0) return undefined;\n if (conditions.length === 1) return conditions[0];\n return { $or: conditions };\n }\n\n /**\n * Build a complete MongoDB query from Rebase options\n *\n * @param options - Rebase fetch options\n * @returns MongoDB filter object\n */\n static buildQuery<M extends Record<string, any>>(options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n searchString?: string;\n properties?: Record<string, any>;\n }): Filter<Document> {\n const conditions: Filter<Document>[] = [];\n\n // Add filter conditions\n if (options.filter) {\n const filterConditions = this.buildFilterConditions<M>(options.filter);\n conditions.push(...filterConditions);\n }\n\n // Add search conditions\n if (options.searchString && options.properties) {\n const searchConditions = this.buildSearchConditions(\n options.searchString,\n options.properties\n );\n if (searchConditions.length > 0) {\n // Search conditions are OR'd together\n const searchFilter = this.combineConditionsWithOr(searchConditions);\n if (searchFilter) {\n conditions.push(searchFilter);\n }\n }\n }\n\n return this.combineConditionsWithAnd(conditions) ?? {};\n }\n\n /**\n * Build MongoDB sort options from Rebase options\n *\n * @param orderBy - Field to order by\n * @param order - Sort direction\n * @returns MongoDB sort object\n */\n static buildSort(\n orderBy?: string,\n order?: \"asc\" | \"desc\"\n ): Record<string, 1 | -1> | undefined {\n if (!orderBy) return undefined;\n return { [orderBy]: order === \"desc\" ? -1 : 1 };\n }\n}\n","/**\n * MongoDB Row Service\n *\n * Implements DataRepository interface for MongoDB.\n * Provides all CRUD operations for rows.\n */\n\nimport { Db, ObjectId, Collection, Document, FindOptions, Filter } from \"mongodb\";\nimport { FilterValues, DataRepository, CollectionConfig, EntityReference } from \"@rebasepro/types\";\nimport { MongoConditionBuilder } from \"./MongoConditionBuilder\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * MongoDB Row Service\n *\n * Implements the DataRepository interface for MongoDB.\n * Provides all CRUD operations for rows stored in MongoDB collections.\n */\nexport class MongoDataService implements DataRepository {\n constructor(private db: Db) { }\n\n /**\n * Get a MongoDB collection by its path\n */\n private getCollection(collectionPath: string): Collection<Document> {\n // Handle nested paths (e.g., \"posts/123/comments\" -> \"posts_123_comments\")\n const collectionName = collectionPath.replace(/\\//g, \"_\");\n return this.db.collection(collectionName);\n }\n\n /**\n * Convert a string ID to ObjectId if it's a valid ObjectId string\n */\n private toObjectId(id: string | number): ObjectId | string | number {\n if (typeof id === \"string\" && ObjectId.isValid(id) && id.length === 24) {\n return new ObjectId(id);\n }\n return id;\n }\n\n /**\n * Convert a MongoDB document to a flat row (`{ id, ...fields }`)\n */\n private documentToRow(doc: Document): Record<string, unknown> {\n const { _id, ...values } = doc;\n return {\n ...this.convertFromMongoValues(values),\n // Spread the canonical id last so it wins over a literal `id` field\n id: _id.toString()\n };\n }\n\n /**\n * Convert values from MongoDB format to Rebase format\n */\n private convertFromMongoValues(values: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(values)) {\n result[key] = this.convertFromMongoValue(value);\n }\n\n return result;\n }\n\n /**\n * Convert a single value from MongoDB format\n */\n private convertFromMongoValue(value: any): any {\n if (value === null || value === undefined) return value;\n\n // Handle ObjectId\n if (value instanceof ObjectId) {\n return value.toString();\n }\n\n // Handle Date\n if (value instanceof Date) {\n return value;\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map(v => this.convertFromMongoValue(v));\n }\n\n // Handle stored EntityReference. New writes are tagged with the\n // `__type: \"reference\"` sentinel (see convertToMongoValue), which is\n // unambiguous. We also accept the legacy shape — an object whose ONLY\n // keys are `id` and `path` — so references written before the sentinel\n // existed still decode. We deliberately do NOT treat any object that\n // merely *contains* `id` and `path` as a reference, because that\n // silently rewrites ordinary embedded sub-documents.\n if (typeof value === \"object\") {\n const keys = Object.keys(value);\n const isTagged = value.__type === \"reference\" && \"id\" in value && \"path\" in value;\n const isLegacy = keys.length === 2 && keys.includes(\"id\") && keys.includes(\"path\");\n if (isTagged || isLegacy) {\n return new EntityReference({\n id: value.id instanceof ObjectId ? value.id.toString() : String(value.id),\n path: value.path,\n driver: value.driver,\n databaseId: value.databaseId\n });\n }\n }\n\n // Handle nested objects\n if (typeof value === \"object\") {\n return this.convertFromMongoValues(value);\n }\n\n return value;\n }\n\n /**\n * Convert values to MongoDB format for storage\n */\n private convertToMongoValues(values: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(values)) {\n result[key] = this.convertToMongoValue(value);\n }\n\n return result;\n }\n\n /**\n * Convert a single value to MongoDB format\n */\n private convertToMongoValue(value: any): any {\n if (value === null || value === undefined) return value;\n\n // Handle EntityReference. Persist with a `__type: \"reference\"` sentinel\n // so it round-trips unambiguously, and preserve `driver`/`databaseId`\n // so cross-datasource pointers don't lose their target on write.\n if (typeof value === \"object\" && value.isEntityReference?.()) {\n const ref: Record<string, unknown> = {\n __type: \"reference\",\n id: ObjectId.isValid(value.id) ? new ObjectId(value.id) : value.id,\n path: value.path\n };\n if (value.driver !== undefined) ref.driver = value.driver;\n if (value.databaseId !== undefined) ref.databaseId = value.databaseId;\n return ref;\n }\n\n // Handle Date\n if (value instanceof Date) {\n return value;\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map(v => this.convertToMongoValue(v));\n }\n\n // Handle nested objects\n if (typeof value === \"object\") {\n return this.convertToMongoValues(value);\n }\n\n return value;\n }\n\n // =============================================================\n // DataRepository Implementation\n // =============================================================\n\n /**\n * Fetch a single row by ID\n */\n async fetchOne<M extends Record<string, any>>(\n collectionPath: string,\n id: string | number,\n _databaseId?: string\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.getCollection(collectionPath);\n const objectId = this.toObjectId(id);\n\n const doc = await collection.findOne({ _id: objectId } as Filter<Document>);\n\n if (!doc) return undefined;\n\n return this.documentToRow(doc);\n }\n\n /**\n * Fetch a collection of rows with optional filtering, ordering, and pagination\n */\n async fetchCollection<M extends Record<string, any>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: any;\n searchString?: string;\n databaseId?: string;\n collection?: CollectionConfig;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<Record<string, unknown>[]> {\n const collection = this.getCollection(collectionPath);\n\n // Build query\n const query = options.rawQuery ?? MongoConditionBuilder.buildQuery<M>({\n filter: options.filter,\n searchString: options.searchString,\n properties: options.collection?.properties ?? {}\n });\n\n // Build find options\n const findOptions: FindOptions = {};\n\n // Apply sorting\n const sort = MongoConditionBuilder.buildSort(options.orderBy, options.order);\n if (sort) {\n findOptions.sort = sort;\n }\n\n // Apply limit\n if (options.limit) {\n findOptions.limit = options.limit;\n }\n\n // Apply pagination (skip-based for now, cursor-based would be better)\n if (options.startAfter !== undefined) {\n findOptions.skip = Number(options.startAfter);\n }\n\n const docs = await collection.find(query, findOptions).toArray();\n\n return docs.map((doc: Document) => this.documentToRow(doc));\n }\n\n /**\n * Search rows by text\n */\n async searchRows<M extends Record<string, any>>(\n collectionPath: string,\n searchString: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n databaseId?: string;\n collection?: CollectionConfig;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<Record<string, unknown>[]> {\n return this.fetchCollection<M>(collectionPath, {\n ...options,\n searchString\n });\n }\n\n /**\n * Count rows in a collection\n */\n async count<M extends Record<string, any>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n databaseId?: string;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<number> {\n const collection = this.getCollection(collectionPath);\n\n const query = options.rawQuery ?? (options.filter\n ? MongoConditionBuilder.buildQuery<M>({ filter: options.filter })\n : {});\n\n return collection.countDocuments(query);\n }\n\n /**\n * Save an row (create or update)\n */\n async save<M extends Record<string, any>>(\n collectionPath: string,\n values: Partial<M>,\n id?: string | number,\n _databaseId?: string\n ): Promise<Record<string, unknown>> {\n const collection = this.getCollection(collectionPath);\n const mongoValues = this.convertToMongoValues(values as Record<string, any>);\n\n if (id) {\n // Update existing row\n const objectId = this.toObjectId(id);\n await collection.updateOne(\n { _id: objectId } as Filter<Document>,\n { $set: mongoValues },\n { upsert: true }\n );\n\n return {\n ...values,\n id: id.toString()\n };\n } else {\n // Create new row\n const newId = new ObjectId();\n await collection.insertOne({\n _id: newId,\n ...mongoValues\n });\n\n return {\n ...values,\n id: newId.toString()\n };\n }\n }\n\n /**\n * Delete an row by ID\n */\n async delete(\n collectionPath: string,\n id: string | number,\n _databaseId?: string\n ): Promise<void> {\n const collection = this.getCollection(collectionPath);\n const objectId = this.toObjectId(id);\n\n const result = await collection.deleteOne({ _id: objectId } as Filter<Document>);\n\n if (result.deletedCount === 0) {\n logger.warn(`Row ${id} not found in collection ${collectionPath}`);\n }\n }\n\n /**\n * Check if a field value is unique in a collection\n */\n async checkUniqueField(\n collectionPath: string,\n fieldName: string,\n value: any,\n excludeEntityId?: string,\n _databaseId?: string\n ): Promise<boolean> {\n const collection = this.getCollection(collectionPath);\n\n const query: Filter<Document> = { [fieldName]: value };\n\n if (excludeEntityId) {\n const objectId = this.toObjectId(excludeEntityId);\n (query as Record<string, unknown>)._id = { $ne: objectId };\n }\n\n const count = await collection.countDocuments(query);\n return count === 0;\n }\n\n /**\n * Generate a new row ID\n */\n generateId(): string {\n return new ObjectId().toString();\n }\n}\n","/**\n * MongoDB Realtime Service\n *\n * Implements RealtimeProvider interface using MongoDB Change Streams.\n * Provides real-time subscriptions to collection and row changes.\n */\n\nimport { Db, ChangeStream, ChangeStreamDocument, Document, ObjectId } from \"mongodb\";\nimport {\n FilterValues,\n RealtimeProvider,\n CollectionSubscriptionConfig,\n SingleSubscriptionConfig,\n WebSocketMessage,\n User\n} from \"@rebasepro/types\";\nimport { WebSocket } from \"ws\";\nimport { MongoDataService } from \"../db/MongoDataService\";\n\nimport type { MongoDriver } from \"./MongoDriver\";\nimport { logger } from \"@rebasepro/server\";\n\ninterface Subscription {\n type: \"collection\" | \"single\";\n config: CollectionSubscriptionConfig | SingleSubscriptionConfig;\n changeStream?: ChangeStream;\n callback?: (data: any) => void;\n authContext?: { uid: string; roles: string[] };\n}\n\n/**\n * MongoDB Realtime Service\n *\n * Implements real-time subscriptions using MongoDB Change Streams.\n * Requires MongoDB replica set for change streams to work.\n */\nexport class MongoRealtimeService implements RealtimeProvider {\n private subscriptions = new Map<string, Subscription>();\n private clients = new Map<string, WebSocket>();\n private dataService: MongoDataService;\n private driver?: MongoDriver;\n\n constructor(private db: Db) {\n this.dataService = new MongoDataService(db);\n }\n\n setDataDriver(driver: MongoDriver) {\n this.driver = driver;\n }\n\n /**\n * Get the collection name from a path\n */\n private getCollectionName(path: string): string {\n return path.replace(/\\//g, \"_\");\n }\n\n /**\n * Subscribe to collection changes\n */\n subscribeToCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (rows: Record<string, unknown>[]) => void\n ): void {\n // Clean up existing subscription if any\n this.unsubscribe(subscriptionId);\n\n const collectionName = this.getCollectionName(config.path);\n const collection = this.db.collection(collectionName);\n\n // Build pipeline for change stream filtering\n const pipeline: Document[] = [];\n\n // Filter by operation types we care about\n pipeline.push({\n $match: {\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] }\n }\n });\n\n try {\n // Create change stream\n const changeStream = collection.watch(pipeline, {\n fullDocument: \"updateLookup\"\n });\n\n const subscription: Subscription = {\n type: \"collection\",\n config,\n changeStream,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyCollection(subscriptionId, config, callback);\n\n // Listen for changes\n changeStream.on(\"change\", async (change: ChangeStreamDocument) => {\n // Re-fetch the entire collection when any change happens\n // This is simpler and ensures consistent sorting/filtering\n await this.fetchAndNotifyCollection(subscriptionId, config, callback);\n });\n\n changeStream.on(\"error\", (error: Error) => {\n logger.error(`Change stream error for subscription ${subscriptionId}`, { error: error });\n });\n\n } catch (error) {\n // Change streams might not be available (e.g., standalone MongoDB)\n logger.warn(\"Change streams not available, falling back to polling\", { error: error });\n\n // Store subscription without change stream for manual notifications\n const subscription: Subscription = {\n type: \"collection\",\n config,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyCollection(subscriptionId, config, callback);\n }\n }\n\n /**\n * Fetch collection and notify callback\n */\n private async fetchAndNotifyCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (rows: Record<string, unknown>[]) => void\n ): Promise<void> {\n try {\n let rows;\n const registryCollection = this.driver?.registry?.getCollectionByPath(config.path);\n\n if (config.authContext && this.driver) {\n const mockUser = { uid: config.authContext.uid,\nroles: config.authContext.roles } as User;\n const authenticatedDriver = await this.driver.withAuth(mockUser);\n rows = await authenticatedDriver.fetchCollection({\n path: config.path,\n collection: registryCollection,\n filter: config.filter as FilterValues<string> | undefined,\n orderBy: config.orderBy,\n order: config.order,\n limit: config.limit,\n startAfter: config.startAfter,\n searchString: config.searchString\n });\n } else {\n rows = await this.dataService.fetchCollection(config.path, {\n filter: config.filter as FilterValues<string> | undefined,\n orderBy: config.orderBy,\n order: config.order,\n limit: config.limit,\n startAfter: config.startAfter,\n searchString: config.searchString,\n collection: registryCollection\n });\n }\n\n if (callback) {\n callback(rows);\n }\n } catch (error) {\n logger.error(`Error fetching collection for subscription ${subscriptionId}`, { error: error });\n }\n }\n\n /**\n * Subscribe to single row changes\n */\n subscribeToOne(\n subscriptionId: string,\n config: SingleSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (row: Record<string, unknown> | null) => void\n ): void {\n // Clean up existing subscription if any\n this.unsubscribe(subscriptionId);\n\n const collectionName = this.getCollectionName(config.path);\n const collection = this.db.collection(collectionName);\n\n // Build pipeline to watch specific document\n const id = typeof config.id === \"string\" && ObjectId.isValid(config.id)\n ? new ObjectId(config.id)\n : config.id;\n\n const pipeline: Document[] = [\n {\n $match: {\n \"documentKey._id\": id,\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] }\n }\n }\n ];\n\n try {\n const changeStream = collection.watch(pipeline, {\n fullDocument: \"updateLookup\"\n });\n\n const subscription: Subscription = {\n type: \"single\",\n config,\n changeStream,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyOne(subscriptionId, config, callback);\n\n // Listen for changes\n changeStream.on(\"change\", async (change: ChangeStreamDocument) => {\n if (change.operationType === \"delete\") {\n if (callback) {\n callback(null);\n }\n } else {\n await this.fetchAndNotifyOne(subscriptionId, config, callback);\n }\n });\n\n changeStream.on(\"error\", (error: Error) => {\n logger.error(`Change stream error for subscription ${subscriptionId}`, { error: error });\n });\n\n } catch (error) {\n logger.warn(\"Change streams not available, falling back to polling\", { error: error });\n\n const subscription: Subscription = {\n type: \"single\",\n config,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyOne(subscriptionId, config, callback);\n }\n }\n\n /**\n * Fetch row and notify callback\n */\n private async fetchAndNotifyOne(\n subscriptionId: string,\n config: SingleSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (row: Record<string, unknown> | null) => void\n ): Promise<void> {\n try {\n let row;\n const registryCollection = this.driver?.registry?.getCollectionByPath(config.path);\n\n if (config.authContext && this.driver) {\n const mockUser = { uid: config.authContext.uid,\nroles: config.authContext.roles } as User;\n const authenticatedDriver = await this.driver.withAuth(mockUser);\n row = await authenticatedDriver.fetchOne({\n path: config.path,\n id: config.id,\n collection: registryCollection\n });\n } else {\n row = await this.dataService.fetchOne(config.path, config.id);\n }\n\n if (callback) {\n callback(row || null);\n }\n } catch (error) {\n logger.error(`Error fetching row for subscription ${subscriptionId}`, { error: error });\n }\n }\n\n /**\n * Unsubscribe from a subscription\n */\n unsubscribe(subscriptionId: string): void {\n const subscription = this.subscriptions.get(subscriptionId);\n if (subscription) {\n if (subscription.changeStream) {\n subscription.changeStream.close().catch((err) => logger.error(\"Operation failed\", { error: err }));\n }\n this.subscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Notify all relevant subscribers of an row update\n * This is called after save/delete operations to push updates\n */\n async notifyUpdate(\n path: string,\n id: string,\n row: Record<string, unknown> | null,\n _databaseId?: string\n ): Promise<void> {\n // Find all subscriptions that might be affected by this update\n for (const [subscriptionId, subscription] of this.subscriptions) {\n if (subscription.type === \"single\") {\n const config = subscription.config as SingleSubscriptionConfig;\n if (config.path === path && config.id.toString() === id) {\n if (subscription.callback) {\n subscription.callback(row);\n }\n }\n } else if (subscription.type === \"collection\") {\n const config = subscription.config as CollectionSubscriptionConfig;\n if (config.path === path) {\n // Re-fetch the collection to get updated data\n await this.fetchAndNotifyCollection(subscriptionId, config, subscription.callback);\n }\n }\n }\n }\n\n /**\n * Get all active subscriptions (for debugging)\n */\n getSubscriptions(): Map<string, Subscription> {\n return this.subscriptions;\n }\n\n /**\n * Close all subscriptions\n */\n async closeAll(): Promise<void> {\n for (const [subscriptionId] of this.subscriptions) {\n this.unsubscribe(subscriptionId);\n }\n }\n\n // =============================================================================\n // WebSocket Client Management (parity with PostgreSQL RealtimeService)\n // =============================================================================\n\n /**\n * Register a WebSocket client for real-time communication\n */\n addClient(clientId: string, ws: WebSocket) {\n this.clients.set(clientId, ws);\n\n ws.on(\"close\", () => {\n this.removeClient(clientId);\n });\n\n ws.on(\"error\", (error) => {\n logger.error(\"WebSocket error for client\", { detail: clientId, error });\n this.removeClient(clientId);\n });\n }\n\n /**\n * Remove a WebSocket client and clean up its subscriptions\n */\n private removeClient(clientId: string) {\n this.clients.delete(clientId);\n }\n\n /**\n * Handle an incoming WebSocket message for subscription management\n */\n async handleClientMessage(\n clientId: string,\n message: { type: string; payload?: any; subscriptionId?: string },\n _authContext?: { uid: string; roles: unknown[] }\n ): Promise<void> {\n const ws = this.clients.get(clientId);\n if (!ws) return;\n\n const authContext = _authContext ? { uid: _authContext.uid,\nroles: (_authContext.roles ?? []).map(String) } : undefined;\n\n switch (message.type) {\n case \"subscribe_collection\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (!subscriptionId) return;\n\n this.subscribeToCollection(\n subscriptionId,\n {\n clientId,\n path: message.payload?.path,\n filter: message.payload?.filter,\n orderBy: message.payload?.orderBy,\n order: message.payload?.order,\n limit: message.payload?.limit,\n startAfter: message.payload?.startAfter,\n searchString: message.payload?.searchString,\n authContext\n },\n (rows) => {\n ws.send(JSON.stringify({\n type: \"collection_update\",\n subscriptionId,\n rows\n }));\n }\n );\n break;\n }\n case \"subscribe_one\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (!subscriptionId) return;\n\n this.subscribeToOne(\n subscriptionId,\n {\n clientId,\n path: message.payload?.path,\n id: message.payload?.id,\n authContext\n },\n (row) => {\n ws.send(JSON.stringify({\n type: \"single_update\",\n subscriptionId,\n row\n }));\n }\n );\n break;\n }\n case \"unsubscribe\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (subscriptionId) {\n this.unsubscribe(subscriptionId);\n }\n break;\n }\n }\n }\n}\n","import { Db, ObjectId } from \"mongodb\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * Deep equality without JSON.stringify.\n * Handles primitives, arrays, Dates, and plain objects recursively.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === \"object\" && typeof b === \"object\") {\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every(k => deepEqual(aObj[k], bObj[k]));\n }\n return false;\n}\n\n/**\n * Shallow comparison to find top-level keys that changed between two objects.\n */\nexport function findChangedFields(\n oldValues: Record<string, unknown>,\n newValues: Record<string, unknown>\n): string[] | null {\n const changed: string[] = [];\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldVal = oldValues[key];\n const newVal = newValues[key];\n\n // Skip internal metadata\n if (key.startsWith(\"__\")) continue;\n\n if (oldVal !== newVal) {\n // For objects/arrays, use structural comparison\n if (\n typeof oldVal === \"object\" && oldVal !== null &&\n typeof newVal === \"object\" && newVal !== null\n ) {\n if (!deepEqual(oldVal, newVal)) {\n changed.push(key);\n }\n } else {\n changed.push(key);\n }\n }\n }\n\n return changed.length > 0 ? changed : null;\n}\n\nexport interface HistoryEntry {\n _id?: ObjectId;\n id: string;\n table_name: string;\n entity_id: string;\n action: \"create\" | \"update\" | \"delete\";\n changed_fields: string[] | null;\n values: Record<string, unknown> | null;\n previous_values: Record<string, unknown> | null;\n updated_by: string | null;\n updated_at: Date;\n}\n\nexport interface RecordHistoryParams {\n tableName: string;\n id: string;\n action: \"create\" | \"update\" | \"delete\";\n values?: Record<string, unknown> | null;\n previousValues?: Record<string, unknown> | null;\n updatedBy?: string | null;\n}\n\nexport interface HistoryRetentionConfig {\n maxEntries: number;\n ttlDays: number;\n}\n\nconst DEFAULT_RETENTION: HistoryRetentionConfig = {\n maxEntries: 200,\n ttlDays: 90\n};\n\nexport class MongoHistoryService {\n public retention: HistoryRetentionConfig;\n\n constructor(\n private db: Db,\n retention?: Partial<HistoryRetentionConfig>\n ) {\n this.retention = { ...DEFAULT_RETENTION,\n...retention };\n }\n\n async recordHistory(params: RecordHistoryParams): Promise<void> {\n const {\n tableName,\n id,\n action,\n values,\n previousValues,\n updatedBy\n } = params;\n\n const changedFields = previousValues && values\n ? findChangedFields(previousValues, values)\n : null;\n\n if (action === \"update\" && (!changedFields || changedFields.length === 0)) {\n return;\n }\n\n try {\n const entry: HistoryEntry = {\n id: new ObjectId().toString(),\n table_name: tableName,\n entity_id: String(id),\n action,\n changed_fields: changedFields,\n values: values || null,\n previous_values: previousValues || null,\n updated_by: updatedBy || null,\n updated_at: new Date()\n };\n\n await this.db.collection(\"__rebase_history\").insertOne(entry);\n\n // Non-blocking prune for this specific row\n this.pruneHistory(String(id), tableName).catch(e => {\n logger.error(`[HistoryService] Failed to prune history for ${tableName}/${id}`, { error: e });\n });\n } catch (error) {\n logger.error(`[HistoryService] Failed to record history for ${tableName}/${id}`, { error: error });\n }\n }\n\n private async pruneHistory(id: string, tableName: string): Promise<void> {\n const collection = this.db.collection(\"__rebase_history\");\n\n // 1. Enforce maxEntries\n const count = await collection.countDocuments({ entity_id: id,\ntable_name: tableName });\n if (count > this.retention.maxEntries) {\n const toDelete = count - this.retention.maxEntries;\n const oldestEntries = await collection\n .find({ entity_id: id,\ntable_name: tableName })\n .sort({ updated_at: 1 })\n .limit(toDelete)\n .toArray();\n\n if (oldestEntries.length > 0) {\n const idsToDelete = oldestEntries.map(entry => entry._id);\n await collection.deleteMany({ _id: { $in: idsToDelete } });\n }\n }\n\n // 2. Enforce ttlDays\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - this.retention.ttlDays);\n\n await collection.deleteMany({\n entity_id: id,\n table_name: tableName,\n updated_at: { $lt: cutoffDate }\n });\n }\n}\n","/**\n * MongoDB DataDriver Delegate\n *\n * Implements the DataDriver interface for Rebase frontend integration.\n * This is the main entry point for Rebase to interact with MongoDB.\n */\n\nimport { Db } from \"mongodb\";\nimport {\n DataDriver,\n DeleteProps,\n Entity,\n CollectionConfig,\n FetchCollectionProps,\n FetchOneProps,\n ListenCollectionProps,\n ListenOneProps,\n SaveProps,\n RebaseCallContext,\n CollectionRegistryInterface,\n User,\n RebaseClient,\n RebaseData,\n RebaseSdkData,\n SecurityRule\n} from \"@rebasepro/types\";\nimport { MongoDataService } from \"../db/MongoDataService\";\nimport { MongoRealtimeService } from \"./MongoRealtimeService\";\nimport { MongoHistoryService } from \"./MongoHistoryService\";\nimport { buildPropertyCallbacks, updateDateAutoValues, buildSdkData, checkOperation } from \"@rebasepro/common\";\nimport { mergeDeep } from \"@rebasepro/utils\";\nimport { Filter, Document } from \"mongodb\";\nimport { ApiError } from \"@rebasepro/server\";\nimport { MongoConditionBuilder } from \"../db/MongoConditionBuilder\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * MongoDB DataDriver Delegate\n *\n * Implements the DataDriver interface for Rebase.\n * Provides all data operations needed by the Rebase frontend.\n */\nexport class MongoDriver implements DataDriver {\n key = \"mongodb\";\n initialised = true;\n\n private dataService: MongoDataService;\n private realtimeService: MongoRealtimeService;\n public historyService: MongoHistoryService;\n public user?: User;\n public data: RebaseSdkData;\n public client?: RebaseClient;\n\n constructor(\n private db: Db,\n realtimeService?: MongoRealtimeService,\n historyService?: MongoHistoryService,\n public readonly registry?: CollectionRegistryInterface,\n user?: User\n ) {\n this.dataService = new MongoDataService(db);\n this.realtimeService = realtimeService ?? new MongoRealtimeService(db);\n this.historyService = historyService ?? new MongoHistoryService(db);\n this.user = user;\n this.data = buildSdkData(this);\n this.realtimeService.setDataDriver(this);\n }\n\n /**\n * Get the current timestamp\n */\n currentTime(): Date {\n return new Date();\n }\n\n /**\n * Resolve a collection's callbacks and property callbacks from the registry.\n * Used by AuthenticatedMongoDriver to apply callbacks after RLS filtering.\n */\n resolveCollectionCallbacks<M extends Record<string, unknown>>(\n collection: CollectionConfig<M> | undefined,\n path: string\n ) {\n if (!collection && !path) return { collection: undefined,\ncallbacks: undefined,\nglobalCallbacks: undefined,\npropertyCallbacks: undefined };\n const registryCollection = this.registry?.getCollectionByPath(path);\n const resolvedCollection = registryCollection\n ? ({ ...collection,\n...registryCollection } as CollectionConfig<M>)\n : (collection as CollectionConfig<M>);\n\n const callbacks = resolvedCollection?.callbacks;\n const globalCallbacks = this.registry?.getGlobalCallbacks();\n const properties = resolvedCollection?.properties;\n let propertyCallbacks;\n if (properties) {\n propertyCallbacks = buildPropertyCallbacks(properties);\n }\n return {\n collection: resolvedCollection,\n callbacks,\n globalCallbacks,\n propertyCallbacks\n };\n }\n\n /**\n * Fetch a collection of rows\n */\n async fetchCollection<M extends Record<string, any>>({\n path,\n collection,\n filter,\n limit,\n startAfter,\n orderBy,\n searchString,\n order\n }: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const rows = await this.dataService.fetchCollection<M>(path, {\n filter,\n limit,\n startAfter,\n orderBy,\n order,\n searchString,\n collection: collection as CollectionConfig\n });\n\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n if (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext; // Backend context\n return Promise.all(rows.map(async (row) => {\n let fetched = row;\n if (globalCallbacks?.afterRead) {\n fetched = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (callbacks?.afterRead) {\n fetched = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (propertyCallbacks?.afterRead) {\n fetched = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n return fetched;\n }));\n }\n\n return rows;\n }\n\n /**\n * Listen to collection changes\n */\n listenCollection<M extends Record<string, any>>({\n path,\n collection,\n filter,\n limit,\n startAfter,\n orderBy,\n searchString,\n order,\n onUpdate,\n onError\n }: ListenCollectionProps<M>): () => void {\n const subscriptionId = this.generateSubscriptionId();\n\n const callback = (rows: Record<string, unknown>[]) => {\n try {\n onUpdate(rows);\n } catch (error) {\n logger.error(\"Error in collection update callback\", { error: error });\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n };\n\n this.realtimeService.subscribeToCollection(\n subscriptionId,\n {\n clientId: \"driver\",\n path,\n filter,\n orderBy,\n order,\n limit,\n startAfter,\n searchString\n },\n callback\n );\n\n // Return unsubscribe function\n return () => {\n this.realtimeService.unsubscribe(subscriptionId);\n };\n }\n\n /**\n * Fetch a single row\n */\n async fetchOne<M extends Record<string, any>>({\n path,\n id,\n databaseId,\n collection\n }: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n let row = await this.dataService.fetchOne<M>(path, id, databaseId);\n\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n if (row && (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext; // Backend context\n let processedRow: Record<string, unknown> = row;\n if (globalCallbacks?.afterRead) {\n processedRow = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n if (callbacks?.afterRead) {\n processedRow = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n if (propertyCallbacks?.afterRead) {\n processedRow = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n row = processedRow;\n }\n\n return row;\n }\n\n /**\n * Listen to row changes\n */\n listenOne<M extends Record<string, any>>({\n path,\n id,\n collection,\n onUpdate,\n onError\n }: ListenOneProps<M>): () => void {\n const subscriptionId = this.generateSubscriptionId();\n\n const callback = (row: Record<string, unknown> | null) => {\n try {\n onUpdate(row);\n } catch (error) {\n logger.error(\"Error in row update callback\", { error: error });\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n };\n\n this.realtimeService.subscribeToOne(\n subscriptionId,\n {\n clientId: \"driver\",\n path,\n id\n },\n callback\n );\n\n // Return unsubscribe function\n return () => {\n this.realtimeService.unsubscribe(subscriptionId);\n };\n }\n\n /**\n * Save an row (create or update)\n */\n async save<M extends Record<string, any>>({\n path,\n id,\n values,\n collection,\n status\n }: SaveProps<M>): Promise<Record<string, unknown>> {\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n let updatedValues = values;\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext;\n\n // Fetch previous values for callbacks AND history recording\n let previousValuesForHistory: Partial<M> | undefined;\n if (status === \"existing\" && id) {\n const existing = await this.dataService.fetchOne<M>(path, id, resolvedCollection?.databaseId);\n if (existing) {\n const { id: _existingId, ...existingValues } = existing;\n previousValuesForHistory = existingValues as Partial<M>;\n }\n }\n\n if (globalCallbacks?.beforeSave || callbacks?.beforeSave || propertyCallbacks?.beforeSave) {\n if (globalCallbacks?.beforeSave) {\n const result = await globalCallbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n\n if (callbacks?.beforeSave) {\n const result = await callbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n\n if (propertyCallbacks?.beforeSave) {\n const result = await propertyCallbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n }\n\n // Apply autoValue timestamps (on_create / on_update) at the application layer.\n if (resolvedCollection?.properties) {\n updatedValues = updateDateAutoValues({\n inputValues: updatedValues,\n properties: resolvedCollection.properties,\n status: status ?? \"new\",\n timestampNowValue: new Date()\n });\n }\n\n try {\n let savedRow = await this.dataService.save<M>(\n path,\n updatedValues,\n id,\n resolvedCollection?.databaseId\n );\n\n if (savedRow && (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n if (globalCallbacks?.afterRead) {\n savedRow = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n if (callbacks?.afterRead) {\n savedRow = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n if (propertyCallbacks?.afterRead) {\n savedRow = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n }\n\n const savedId = savedRow.id as string | number;\n const { id: _savedId, ...savedValues } = savedRow;\n\n if (globalCallbacks?.afterSave || callbacks?.afterSave || propertyCallbacks?.afterSave) {\n if (globalCallbacks?.afterSave) {\n await globalCallbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n if (callbacks?.afterSave) {\n await callbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues as Partial<M>,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterSave) {\n await propertyCallbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n }\n\n // Record row history (fire-and-forget, never blocks the save)\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n tableName: path,\n id: savedId.toString(),\n action: status === \"new\" ? \"create\" : \"update\",\n values: savedValues as Record<string, unknown>,\n previousValues: previousValuesForHistory as Record<string, unknown> | undefined,\n updatedBy: this.user?.uid\n }).catch(err => {\n logger.error(`Failed to record history for ${path}/${savedId}`, { error: err });\n });\n }\n\n // Notify real-time subscribers\n await this.realtimeService.notifyUpdate(\n path,\n savedId.toString(),\n savedRow\n );\n\n return savedRow;\n } catch (error) {\n if (callbacks?.afterSaveError || propertyCallbacks?.afterSaveError) {\n if (callbacks?.afterSaveError) {\n await callbacks.afterSaveError({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: id || \"unknown\",\n values: updatedValues,\n previousValues: undefined,\n status,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterSaveError) {\n await propertyCallbacks.afterSaveError({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: id || \"unknown\",\n values: updatedValues,\n previousValues: undefined,\n status,\n context: contextForCallback\n });\n }\n }\n throw error;\n }\n }\n\n /**\n * Delete an row\n */\n async delete<M extends Record<string, any>>({\n row,\n collection\n }: DeleteProps<M>): Promise<void> {\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, row.path);\n\n const callbackRow: Record<string, unknown> = { id: row.id, ...(row.values ?? {}) };\n\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext;\n\n if (globalCallbacks?.beforeDelete || callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {\n let preventDefault = false;\n if (globalCallbacks?.beforeDelete) {\n const result = await globalCallbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (callbacks?.beforeDelete) {\n const result = await callbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (propertyCallbacks?.beforeDelete) {\n const result = await propertyCallbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (preventDefault) {\n return;\n }\n }\n\n await this.dataService.delete(row.path, row.id);\n\n if (globalCallbacks?.afterDelete || callbacks?.afterDelete || propertyCallbacks?.afterDelete) {\n if (globalCallbacks?.afterDelete) {\n await globalCallbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n if (callbacks?.afterDelete) {\n await callbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterDelete) {\n await propertyCallbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n }\n\n // Record history\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n action: \"delete\",\n id: String(row.id),\n tableName: row.path,\n previousValues: row.values,\n updatedBy: this.user?.uid\n }).catch(err => {\n logger.error(`Failed to record history for ${row.path}/${row.id}`, { error: err });\n });\n }\n\n // Notify subscribers of the deletion\n await this.realtimeService.notifyUpdate(row.path, String(row.id), null);\n }\n\n /**\n * Check if a field value is unique\n */\n async checkUniqueField(\n path: string,\n name: string,\n value: any,\n id?: string,\n collection?: CollectionConfig\n ): Promise<boolean> {\n return this.dataService.checkUniqueField(path, name, value, id);\n }\n\n /**\n * Generate a new row ID\n */\n generateId(path: string, collection?: CollectionConfig): string {\n return this.dataService.generateId();\n }\n\n /**\n * Count rows in a collection\n */\n async count<M extends Record<string, any>>({\n path,\n collection,\n filter\n }: FetchCollectionProps<M>): Promise<number> {\n return this.dataService.count<M>(path, { filter });\n }\n\n /**\n * Generate a unique subscription ID\n */\n private generateSubscriptionId(): string {\n return `mongo_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Check if the delegate is ready\n */\n isReady(): boolean {\n return this.initialised;\n }\n\n /**\n * Get the underlying row service for direct access\n */\n getDataService(): MongoDataService {\n return this.dataService;\n }\n\n /**\n * Get the underlying realtime service for direct access\n */\n getRealtimeService(): MongoRealtimeService {\n return this.realtimeService;\n }\n\n /**\n * Scope the MongoDriver with an authenticated user context\n */\n async withAuth(user: User): Promise<DataDriver> {\n return new AuthenticatedMongoDriver(this, user);\n }\n}\n\nexport class AuthenticatedMongoDriver implements DataDriver {\n key = \"mongodb\";\n initialised = true;\n public user: User;\n public data: RebaseSdkData;\n\n constructor(public delegate: MongoDriver, user: User) {\n this.user = user;\n this.data = buildSdkData(this);\n }\n\n currentTime(): Date {\n return this.delegate.currentTime();\n }\n\n async fetchCollection<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const rlsFilter = buildMongoFilterFromSecurityRules(resolvedCollection, this.user, \"select\");\n if (rlsFilter === null) {\n return [];\n }\n\n const userQuery = MongoConditionBuilder.buildQuery({\n filter: props.filter,\n searchString: props.searchString,\n properties: resolvedCollection?.properties\n });\n\n const combinedQuery = Object.keys(rlsFilter).length > 0\n ? ({ $and: [userQuery, rlsFilter] } as Filter<Document>)\n : userQuery;\n\n const originalService = this.delegate.getDataService();\n const rows = await originalService.fetchCollection<M>(props.path, {\n ...props,\n rawQuery: combinedQuery,\n collection: resolvedCollection\n });\n\n const { callbacks, globalCallbacks, propertyCallbacks } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n\n if (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.delegate.client,\n storageSource: this.delegate.client?.storage\n } as unknown as RebaseCallContext;\n return Promise.all(rows.map(async (row) => {\n let fetched = row;\n if (globalCallbacks?.afterRead) {\n fetched = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (callbacks?.afterRead) {\n fetched = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (propertyCallbacks?.afterRead) {\n fetched = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n return fetched;\n }));\n }\n\n return rows;\n }\n\n listenCollection<M extends Record<string, any>>(props: ListenCollectionProps<M>): () => void {\n const unsubscribe = this.delegate.listenCollection(props);\n const authContext = { uid: this.user.uid,\nroles: this.user.roles ?? [] };\n const subscriptions = this.delegate.getRealtimeService().getSubscriptions();\n const lastEntry = Array.from(subscriptions.entries()).pop();\n const lastSub = lastEntry?.[1];\n if (lastSub && lastSub.config.clientId === \"driver\") {\n lastSub.authContext = authContext;\n }\n return unsubscribe;\n }\n\n async fetchOne<M extends Record<string, any>>(props: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const row = await this.delegate.fetchOne(props);\n if (row) {\n const authorized = checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(row, props.path), \"select\", { onUnknown: \"deny\" });\n if (!authorized) {\n return undefined;\n }\n }\n return row;\n }\n\n listenOne<M extends Record<string, any>>(props: ListenOneProps<M>): () => void {\n const unsubscribe = this.delegate.listenOne(props);\n const authContext = { uid: this.user.uid,\nroles: this.user.roles ?? [] };\n const subscriptions = this.delegate.getRealtimeService().getSubscriptions();\n const lastEntry = Array.from(subscriptions.entries()).pop();\n const lastSub = lastEntry?.[1];\n if (lastSub && lastSub.config.clientId === \"driver\") {\n lastSub.authContext = authContext;\n }\n return unsubscribe;\n }\n\n async save<M extends Record<string, any>>(props: SaveProps<M>): Promise<Record<string, unknown>> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n\n if (props.status === \"existing\" && props.id) {\n const existing = await this.delegate.fetchOne({ path: props.path,\nid: props.id,\ncollection: resolvedCollection });\n if (!existing || !checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(existing, props.path), \"update\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n } else {\n const tempEntity = { id: props.id || \"new\",\npath: props.path,\nvalues: props.values } as Entity;\n if (!checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, tempEntity, \"insert\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n }\n\n const saved = await this.delegate.save({\n ...props,\n collection: resolvedCollection\n });\n\n // After save / withCheck rules verification\n if (!checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(saved, props.path), props.status === \"existing\" ? \"update\" : \"insert\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n\n return saved;\n }\n\n async delete<M extends Record<string, any>>(props: DeleteProps<M>): Promise<void> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.row.path);\n\n const existing = await this.delegate.fetchOne({ path: props.row.path,\nid: props.row.id,\ncollection: resolvedCollection });\n if (!existing || !checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(existing, props.row.path), \"delete\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n\n return this.delegate.delete(props);\n }\n\n async checkUniqueField(\n path: string,\n name: string,\n value: any,\n id?: string,\n collection?: CollectionConfig\n ): Promise<boolean> {\n return this.delegate.checkUniqueField(path, name, value, id, collection);\n }\n\n generateId(path: string, collection?: CollectionConfig): string {\n return this.delegate.generateId(path, collection);\n }\n\n async count<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<number> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const rlsFilter = buildMongoFilterFromSecurityRules(resolvedCollection, this.user, \"select\");\n if (rlsFilter === null) {\n return 0;\n }\n\n const userQuery = MongoConditionBuilder.buildQuery({\n filter: props.filter,\n searchString: props.searchString,\n properties: resolvedCollection?.properties\n });\n\n const combinedQuery = Object.keys(rlsFilter).length > 0\n ? ({ $and: [userQuery, rlsFilter] } as Filter<Document>)\n : userQuery;\n\n const originalService = this.delegate.getDataService();\n return originalService.count(props.path, {\n ...props,\n rawQuery: combinedQuery\n });\n }\n\n isReady(): boolean {\n return this.delegate.isReady();\n }\n}\n\n/**\n * Wrap a flat row into the Entity shape expected by `checkOperation`,\n * which evaluates security rules against `row.values`.\n */\nfunction rowToEntityForCheck(row: Record<string, unknown>, path: string): Entity {\n return {\n id: row.id as string | number,\n path,\n values: row\n };\n}\n\nfunction getMongoFilterForSQL(sqlString: string, user: User): Filter<Document> | null {\n let cleanedSQL = sqlString.trim();\n while (cleanedSQL.startsWith(\"(\") && cleanedSQL.endsWith(\")\")) {\n let openCount = 0;\n let isEnclosing = true;\n for (let i = 0; i < cleanedSQL.length - 1; i++) {\n if (cleanedSQL[i] === \"(\") openCount++;\n else if (cleanedSQL[i] === \")\") openCount--;\n if (openCount === 0) {\n isEnclosing = false;\n break;\n }\n }\n if (isEnclosing) {\n cleanedSQL = cleanedSQL.substring(1, cleanedSQL.length - 1).trim();\n } else {\n break;\n }\n }\n\n const splitByTopLevel = (str: string, delimiter: string) => {\n const parts: string[] = [];\n let current = \"\";\n let openCount = 0;\n let i = 0;\n while (i < str.length) {\n if (str[i] === \"(\") openCount++;\n else if (str[i] === \")\") openCount--;\n\n if (openCount === 0 && str.substring(i).toUpperCase().startsWith(delimiter)) {\n parts.push(current);\n current = \"\";\n i += delimiter.length;\n } else {\n current += str[i];\n i++;\n }\n }\n parts.push(current);\n return parts;\n };\n\n const orParts = splitByTopLevel(cleanedSQL, \" OR \");\n if (orParts.length > 1) {\n const subFilters = orParts.map(part => getMongoFilterForSQL(part, user)).filter(f => f !== null) as Filter<Document>[];\n if (subFilters.length === 0) return null;\n if (subFilters.length === 1) return subFilters[0];\n return { $or: subFilters } as Filter<Document>;\n }\n\n const andParts = splitByTopLevel(cleanedSQL, \" AND \");\n if (andParts.length > 1) {\n const subFilters = andParts.map(part => getMongoFilterForSQL(part, user)).filter(f => f !== null) as Filter<Document>[];\n if (subFilters.length === 0) return null;\n if (subFilters.length === 1) return subFilters[0];\n return { $and: subFilters } as Filter<Document>;\n }\n\n const roleIntersectMatch = cleanedSQL.match(/string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*&&\\s*ARRAY\\[(.*?)\\]/i);\n if (roleIntersectMatch && roleIntersectMatch[1]) {\n const requiredRoles = roleIntersectMatch[1].split(\",\").map(r => r.trim().replace(/'/g, \"\"));\n const userRoles = user.roles || [];\n const matches = requiredRoles.some(r => userRoles.includes(r));\n return matches ? {} : { _id: { $exists: false } };\n }\n\n const roleContainMatch = cleanedSQL.match(/string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*@>\\s*ARRAY\\[(.*?)\\]/i);\n if (roleContainMatch && roleContainMatch[1]) {\n const requiredRoles = roleContainMatch[1].split(\",\").map(r => r.trim().replace(/'/g, \"\"));\n const userRoles = user.roles || [];\n const matches = requiredRoles.every(r => userRoles.includes(r));\n return matches ? {} : { _id: { $exists: false } };\n }\n\n const pattern1 = new RegExp(\"^\\\\{?([a-zA-Z0-9_]+)\\\\}?\\\\s*=\\\\s*(?:current_setting\\\\s*\\\\(\\\\s*'app\\\\.user_id'\\\\s*\\\\)|auth\\\\.uid\\\\(\\\\))\");\n const pattern2 = new RegExp(\"^(?:current_setting\\\\s*\\\\(\\\\s*'app\\\\.user_id'\\\\s*\\\\)|auth\\\\.uid\\\\(\\\\))\\\\s*=\\\\s*\\\\{?([a-zA-Z0-9_]+)\\\\}?\");\n\n const match1 = cleanedSQL.match(pattern1);\n if (match1 && match1[1]) {\n return { [match1[1]]: user.uid };\n }\n\n const match2 = cleanedSQL.match(pattern2);\n if (match2 && match2[1]) {\n return { [match2[1]]: user.uid };\n }\n\n const simpleEqualityMatch = cleanedSQL.match(/^\\{?([\\w_]+)\\}?\\s*(=|!=)\\s*'([^']+)'$/i);\n if (simpleEqualityMatch) {\n const field = simpleEqualityMatch[1];\n const operator = simpleEqualityMatch[2];\n const value = simpleEqualityMatch[3];\n if (operator === \"=\") return { [field]: value };\n if (operator === \"!=\") return { [field]: { $ne: value } };\n }\n\n return {};\n}\n\nfunction getMongoFilterForRule(rule: SecurityRule, user: User): Filter<Document> | null {\n if (rule.access === \"public\") return {};\n\n const filters: Filter<Document>[] = [];\n\n if (rule.ownerField) {\n filters.push({ [rule.ownerField]: user.uid });\n }\n\n if (rule.using) {\n const f = getMongoFilterForSQL(rule.using, user);\n if (f) filters.push(f);\n }\n\n if (rule.withCheck) {\n const f = getMongoFilterForSQL(rule.withCheck, user);\n if (f) filters.push(f);\n }\n\n if (filters.length === 0) return {};\n if (filters.length === 1) return filters[0];\n return { $and: filters } as Filter<Document>;\n}\n\nfunction buildMongoFilterFromSecurityRules<M extends Record<string, any>>(\n collection: CollectionConfig<M> | undefined,\n user: User,\n targetOperation: \"select\" | \"insert\" | \"update\" | \"delete\"\n): Filter<Document> | null {\n if (!collection || !collection.securityRules || collection.securityRules.length === 0) {\n return {};\n }\n\n const applicableRules = collection.securityRules.filter((r: SecurityRule) =>\n r.operation === targetOperation ||\n r.operation === \"all\" ||\n r.operations?.includes(targetOperation) ||\n r.operations?.includes(\"all\")\n );\n\n if (applicableRules.length === 0) {\n return null;\n }\n\n const userRoleIds = user.roles ?? [];\n const userRoles = [...userRoleIds, \"public\"];\n const roleApplicableRules = applicableRules.filter((rule: SecurityRule) => {\n if (!rule.roles || rule.roles.length === 0) return true;\n return rule.roles.some((r: string) => userRoles.includes(r));\n });\n\n if (roleApplicableRules.length === 0) {\n return null;\n }\n\n const permissiveFilters: Filter<Document>[] = [];\n const restrictiveFilters: Filter<Document>[] = [];\n\n for (const rule of roleApplicableRules) {\n const mode = rule.mode || \"permissive\";\n const filter = getMongoFilterForRule(rule, user);\n if (filter === null) {\n if (mode === \"restrictive\") {\n return null;\n }\n continue;\n }\n\n if (mode === \"restrictive\") {\n restrictiveFilters.push(filter);\n } else {\n permissiveFilters.push(filter);\n }\n }\n\n const finalAnds: Filter<Document>[] = [];\n\n if (permissiveFilters.length > 0) {\n const hasAlwaysTruePermissive = permissiveFilters.some(f => Object.keys(f).length === 0);\n if (!hasAlwaysTruePermissive) {\n if (permissiveFilters.length === 1) {\n finalAnds.push(permissiveFilters[0]);\n } else {\n finalAnds.push({ $or: permissiveFilters } as Filter<Document>);\n }\n }\n } else {\n return null;\n }\n\n if (restrictiveFilters.length > 0) {\n for (const rf of restrictiveFilters) {\n if (Object.keys(rf).length > 0) {\n finalAnds.push(rf);\n }\n }\n }\n\n if (finalAnds.length === 0) return {};\n if (finalAnds.length === 1) return finalAnds[0];\n return { $and: finalAnds } as Filter<Document>;\n}\n","/**\n * MongoDB Backend Factory\n *\n * This module provides factory functions for creating MongoDB backend instances.\n * It abstracts the creation of drivers, realtime services, and row services.\n */\n\nimport { Db, MongoClient } from \"mongodb\";\nimport { DataDriver, CollectionConfig } from \"@rebasepro/types\";\n\nimport { MongoDataService } from \"./db/MongoDataService\";\nimport { MongoRealtimeService } from \"./services/MongoRealtimeService\";\nimport { MongoDriver } from \"./services/MongoDriver\";\nimport { MongoHistoryService, HistoryRetentionConfig } from \"./services/MongoHistoryService\";\nimport { MongoDBConnection } from \"./connection\";\nimport { BackendConfig, BackendInstance, CollectionRegistryInterface, DataRepository, RealtimeProvider, DatabaseConnection, DatabaseAdmin, DocumentAdmin, SchemaAdmin, HealthCheckResult } from \"@rebasepro/types\";\n\n/**\n * Configuration for creating a MongoDB backend.\n */\nexport interface MongoBackendConfig extends BackendConfig {\n type: \"mongodb\";\n /** MongoDB database instance */\n connection: Db;\n /** MongoDB client (for connection management) */\n client: MongoClient;\n /** Collections to register (optional, can be registered later) */\n collections?: CollectionConfig[];\n /** History retention configuration */\n historyRetention?: Partial<HistoryRetentionConfig>;\n}\n\n/**\n * MongoDB-specific backend instance with additional MongoDB types.\n */\nexport interface MongoBackendInstance extends BackendInstance {\n /** The MongoDB database instance */\n db: Db;\n /** The MongoDB client */\n client: MongoClient;\n /** MongoDB DataDriver for use with Rebase */\n driver: DataDriver;\n /** Entity service for direct database operations */\n dataService: MongoDataService;\n /** Realtime service for subscriptions */\n realtimeService: MongoRealtimeService;\n /** Admin capabilities (DocumentAdmin + SchemaAdmin) */\n admin: DatabaseAdmin;\n}\n\n// =============================================================================\n// Simple Collection Registry\n// =============================================================================\n\n/**\n * Simple in-memory collection registry for MongoDB.\n */\nexport class MongoCollectionRegistry implements CollectionRegistryInterface {\n private collections = new Map<string, CollectionConfig>();\n private _globalCallbacks?: any;\n\n /**\n * Register a collection\n */\n register(collection: CollectionConfig): void {\n this.collections.set(collection.name, collection);\n }\n\n /**\n * Get a collection by its path\n */\n getCollectionByPath(path: string): CollectionConfig | undefined {\n return this.collections.get(path);\n }\n\n /**\n * Get all registered collections\n */\n getCollections(): CollectionConfig[] {\n return Array.from(this.collections.values());\n }\n\n /**\n * Get the currently registered global callbacks, if any.\n */\n getGlobalCallbacks(): any | undefined {\n return this._globalCallbacks;\n }\n\n /**\n * Set global lifecycle callbacks that apply to every collection.\n */\n setGlobalCallbacks(callbacks: any): void {\n this._globalCallbacks = callbacks;\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Create a complete MongoDB backend instance.\n *\n * This factory function creates all the necessary services for a MongoDB backend:\n * - MongoDBConnection (database connection wrapper)\n * - MongoDataService (implements DataRepository)\n * - MongoRealtimeService (implements RealtimeProvider)\n * - MongoCollectionRegistry (implements CollectionRegistryInterface)\n * - MongoDriver (for Rebase integration)\n *\n * @example\n * ```typescript\n * import { createMongoBackend } from \"@rebasepro/server-mongo\";\n *\n * const client = new MongoClient(\"mongodb://localhost:27017\");\n * await client.connect();\n * const db = client.db(\"my_database\");\n *\n * const backend = createMongoBackend({\n * type: \"mongodb\",\n * connection: db,\n * client: client,\n * collections: myCollections\n * });\n *\n * // Use the backend\n * const rows = await backend.entityRepository.fetchCollection(\"users\", {});\n * ```\n */\nexport function createMongoBackend(config: MongoBackendConfig): MongoBackendInstance {\n const { connection: db, client, collections } = config;\n\n // Create collection registry\n const collectionRegistry = new MongoCollectionRegistry();\n\n // Register collections if provided\n if (collections) {\n collections.forEach(collection => collectionRegistry.register(collection));\n }\n\n // Create services\n const dataService = new MongoDataService(db);\n const realtimeService = new MongoRealtimeService(db);\n const historyService = new MongoHistoryService(db, config.historyRetention);\n const driver = new MongoDriver(db, realtimeService, historyService, collectionRegistry);\n const mongoConnection = new MongoDBConnection(db, client);\n\n // Build admin capabilities for MongoDB\n const admin: DatabaseAdmin = {\n async executeAggregate(pipeline: Record<string, unknown>[]) {\n // Run aggregation on a collection — requires a target collection\n // from the pipeline's $match or $lookup stage:\n const firstStage = pipeline[0];\n const collName = typeof firstStage.$from === \"string\" ? firstStage.$from : \"__admin__\";\n const cursor = db.collection(collName).aggregate(pipeline);\n return await cursor.toArray() as Record<string, unknown>[];\n },\n async fetchCollectionStats(collectionName: string) {\n const stats = await db.command({ collStats: collectionName }) as { count: number; size: number };\n return { count: stats.count,\nsizeBytes: stats.size };\n },\n async fetchUnmappedTables(mappedPaths?: string[]) {\n const allCollections = await db.listCollections().toArray();\n const names = allCollections.map(c => c.name).filter(n => !n.startsWith(\"system.\"));\n if (!mappedPaths || mappedPaths.length === 0) return names;\n const mappedSet = new Set(mappedPaths.map(p => p.toLowerCase()));\n return names.filter(n => !mappedSet.has(n.toLowerCase()));\n },\n async fetchTableMetadata(collectionName: string) {\n // Sample a document to infer fields\n const sample = await db.collection(collectionName).findOne();\n if (!sample) return { columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n const columns = Object.entries(sample).map(([key, value]) => ({\n column_name: key,\n data_type: typeof value,\n udt_name: typeof value,\n is_nullable: \"YES\",\n column_default: null,\n character_maximum_length: null\n }));\n return { columns,\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n }\n } satisfies DocumentAdmin & SchemaAdmin;\n\n return {\n // Abstract interface implementations\n connection: mongoConnection,\n entityRepository: dataService,\n realtimeProvider: realtimeService,\n collectionRegistry: collectionRegistry,\n admin,\n\n // Lifecycle\n async initialize() {\n // Connection is already established via the MongoClient constructor\n },\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n await db.command({ ping: 1 });\n return { healthy: true,\nlatencyMs: Date.now() - start };\n } catch {\n return { healthy: false,\nlatencyMs: Date.now() - start };\n }\n },\n async destroy() {\n await client.close();\n },\n\n // MongoDB-specific accessors\n db,\n client,\n driver,\n dataService,\n realtimeService\n };\n}\n\n/**\n * Create a MongoDB DataDriver.\n *\n * This is a convenience function when you only need the DataDriver\n * without the full backend instance.\n *\n * @example\n * ```typescript\n * import { createMongoDelegate } from \"@rebasepro/server-mongo\";\n *\n * const delegate = createMongoDelegate(db);\n * ```\n */\nexport function createMongoDelegate(\n db: Db,\n realtimeService?: MongoRealtimeService,\n historyService?: MongoHistoryService,\n registry?: CollectionRegistryInterface\n): MongoDriver {\n const realtime = realtimeService ?? new MongoRealtimeService(db);\n const history = historyService ?? new MongoHistoryService(db);\n return new MongoDriver(db, realtime, history, registry);\n}\n\n/**\n * Create a RealtimeService for MongoDB.\n *\n * @example\n * ```typescript\n * import { createMongoRealtimeService } from \"@rebasepro/server-mongo\";\n *\n * const realtimeService = createMongoRealtimeService(db);\n * ```\n */\nexport function createMongoRealtimeService(db: Db): MongoRealtimeService {\n return new MongoRealtimeService(db);\n}\n\n/**\n * Create a MongoDB row repository.\n *\n * @example\n * ```typescript\n * import { createMongoEntityRepository } from \"@rebasepro/server-mongo\";\n *\n * const repository = createMongoEntityRepository(db);\n * const users = await repository.fetchCollection(\"users\", {});\n * ```\n */\nexport function createMongoEntityRepository(db: Db): DataRepository {\n return new MongoDataService(db);\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a backend config is for MongoDB.\n */\nexport function isMongoBackendConfig(config: BackendConfig): config is MongoBackendConfig {\n return config.type === \"mongodb\" &&\n typeof (config as MongoBackendConfig).connection !== \"undefined\" &&\n typeof (config as MongoBackendConfig).client !== \"undefined\";\n}\n\n/**\n * Check if a driver config is for MongoDB.\n */\nexport function isMongoDriverConfig(obj: unknown): obj is { type: \"mongodb\"; connection: Db; client: MongoClient } {\n return typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as Record<string, unknown>).type === \"mongodb\" &&\n \"connection\" in obj &&\n \"client\" in obj;\n}\n","import { Db, ObjectId } from \"mongodb\";\n\n/** Loose document type that allows string _id values (Rebase convention). */\nexport interface MongoDoc { _id?: string; [key: string]: any; }\nimport {\n UserRepository,\n RoleRepository,\n TokenRepository,\n AuthRepository,\n UserData,\n CreateUserData,\n RoleData,\n CreateRoleData,\n RefreshTokenInfo,\n RefreshTokenSession,\n PasswordResetTokenInfo,\n MagicLinkTokenInfo,\n UserIdentityData,\n ListUsersOptions,\n PaginatedUsersResult,\n MfaFactor,\n MfaChallengeInfo\n} from \"@rebasepro/server\";\n\nexport type Role = RoleData;\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction toUser(doc: any): UserData {\n return {\n id: doc._id || doc.id,\n email: doc.email,\n passwordHash: doc.passwordHash ?? null,\n displayName: doc.displayName ?? null,\n photoUrl: doc.photoUrl ?? null,\n emailVerified: doc.emailVerified ?? false,\n emailVerificationToken: doc.emailVerificationToken ?? null,\n emailVerificationSentAt: doc.emailVerificationSentAt ? new Date(doc.emailVerificationSentAt) : null,\n createdAt: new Date(doc.createdAt),\n updatedAt: new Date(doc.updatedAt)\n };\n}\n\nexport class MongoUserService implements UserRepository {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_users\");\n }\n\n private get identitiesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_user_identities\");\n }\n\n private get userRolesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_user_roles\");\n }\n\n private get rolesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_roles\");\n }\n\n async createUser(data: CreateUserData): Promise<UserData> {\n const id = new ObjectId().toString();\n const now = new Date();\n const doc = {\n _id: id,\n id,\n email: data.email.toLowerCase(),\n passwordHash: data.passwordHash ?? null,\n displayName: data.displayName ?? null,\n photoUrl: data.photoUrl ?? null,\n emailVerified: data.emailVerified ?? false,\n createdAt: now,\n updatedAt: now\n };\n await this.collection.insertOne(doc);\n return toUser(doc);\n }\n\n async getUserById(id: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ id });\n return doc ? toUser(doc) : null;\n }\n\n async getUserByEmail(email: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ email: email.toLowerCase() });\n return doc ? toUser(doc) : null;\n }\n\n async getUserByIdentity(provider: string, providerId: string): Promise<UserData | null> {\n const identity = await this.identitiesCollection.findOne({ provider,\nproviderId });\n if (!identity) return null;\n return this.getUserById(identity.uid);\n }\n\n async getUserIdentities(uid: string): Promise<UserIdentityData[]> {\n const docs = await this.identitiesCollection.find({ uid }).toArray();\n return docs.map(doc => ({\n id: doc.id,\n uid: doc.uid,\n provider: doc.provider,\n providerId: doc.providerId,\n profileData: doc.profileData ?? null,\n createdAt: new Date(doc.createdAt),\n updatedAt: new Date(doc.updatedAt)\n }));\n }\n\n async linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n const now = new Date();\n await this.identitiesCollection.updateOne(\n { provider,\nproviderId },\n {\n $setOnInsert: {\n _id: new ObjectId().toString(),\n id: new ObjectId().toString(),\n uid,\n provider,\n providerId,\n createdAt: now\n },\n $set: {\n profileData: profileData ?? null,\n updatedAt: now\n }\n },\n { upsert: true }\n );\n }\n\n async updateUser(id: string, data: Partial<Omit<CreateUserData, \"id\">>): Promise<UserData | null> {\n const updateData: Record<string, unknown> = { ...data,\nupdatedAt: new Date() };\n if (typeof updateData.email === \"string\") updateData.email = updateData.email.toLowerCase();\n\n await this.collection.updateOne({ id }, { $set: updateData });\n return this.getUserById(id);\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.collection.deleteOne({ id });\n await this.identitiesCollection.deleteMany({ uid: id });\n await this.userRolesCollection.deleteMany({ uid: id });\n }\n\n async listUsers(): Promise<UserData[]> {\n const docs = await this.collection.find().toArray();\n return docs.map(toUser);\n }\n\n async listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult> {\n const limit = options?.limit ?? 25;\n const offset = options?.offset ?? 0;\n const search = options?.search?.trim() || \"\";\n const orderBy = options?.orderBy || \"createdAt\";\n const orderDir = options?.orderDir || \"desc\";\n const roleId = options?.roleId;\n\n const query: Record<string, unknown> = {};\n\n if (search) {\n const escapedSearch = escapeRegExp(search);\n query.$or = [\n { email: { $regex: escapedSearch,\n$options: \"i\" } },\n { displayName: { $regex: escapedSearch,\n$options: \"i\" } }\n ];\n }\n\n if (roleId) {\n const userRoles = await this.userRolesCollection.find({ roleId }).toArray();\n const userIds = userRoles.map(ur => ur.uid);\n query.id = { $in: userIds };\n }\n\n const sort: Record<string, 1 | -1> = {};\n sort[orderBy] = orderDir === \"asc\" ? 1 : -1;\n\n const total = await this.collection.countDocuments(query);\n const docs = await this.collection.find(query).sort(sort).skip(offset).limit(limit).toArray();\n\n return {\n users: docs.map(toUser),\n total,\n limit,\n offset\n };\n }\n\n async updatePassword(id: string, passwordHash: string): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { passwordHash,\nupdatedAt: new Date() } }\n );\n }\n\n async setEmailVerified(id: string, verified: boolean): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { emailVerified: verified,\nemailVerificationToken: null,\nupdatedAt: new Date() } }\n );\n }\n\n async setVerificationToken(id: string, token: string | null): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { emailVerificationToken: token,\nemailVerificationSentAt: token ? new Date() : null,\nupdatedAt: new Date() } }\n );\n }\n\n async getUserByVerificationToken(token: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ emailVerificationToken: token });\n return doc ? toUser(doc) : null;\n }\n\n async getUserRoles(uid: string): Promise<RoleData[]> {\n const userRoles = await this.userRolesCollection.find({ uid }).toArray();\n const roleIds = userRoles.map(ur => ur.roleId);\n if (roleIds.length === 0) return [];\n\n const roles = await this.rolesCollection.find({ id: { $in: roleIds } }).toArray();\n return roles.map(r => ({\n id: r.id,\n name: r.name,\n isAdmin: r.isAdmin ?? false,\n defaultPermissions: r.defaultPermissions ?? null,\n collectionPermissions: r.collectionPermissions ?? null\n }));\n }\n\n async getUserRoleIds(uid: string): Promise<string[]> {\n const userRoles = await this.userRolesCollection.find({ uid }).toArray();\n return userRoles.map(ur => ur.roleId);\n }\n\n async setUserRoles(uid: string, roleIds: string[]): Promise<void> {\n await this.userRolesCollection.deleteMany({ uid });\n if (roleIds.length > 0) {\n const docs = roleIds.map(roleId => ({\n _id: new ObjectId().toString(),\n uid,\n roleId\n }));\n await this.userRolesCollection.insertMany(docs);\n }\n }\n\n async assignDefaultRole(uid: string, roleId: string): Promise<void> {\n await this.userRolesCollection.updateOne(\n { uid,\nroleId },\n { $setOnInsert: { _id: new ObjectId().toString(),\nuid,\nroleId } },\n { upsert: true }\n );\n }\n\n async getUserWithRoles(uid: string): Promise<{ user: UserData; roles: RoleData[] } | null> {\n const user = await this.getUserById(uid);\n if (!user) return null;\n const roles = await this.getUserRoles(uid);\n return { user,\nroles };\n }\n}\n\nexport class MongoRoleService implements RoleRepository {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_roles\");\n }\n\n async getRoleById(id: string): Promise<RoleData | null> {\n const doc = await this.collection.findOne({ id });\n if (!doc) return null;\n return {\n id: doc.id,\n name: doc.name,\n isAdmin: doc.isAdmin ?? false,\n defaultPermissions: doc.defaultPermissions ?? null,\n collectionPermissions: doc.collectionPermissions ?? null\n };\n }\n\n async listRoles(): Promise<RoleData[]> {\n const docs = await this.collection.find().sort({ name: 1 }).toArray();\n return docs.map(doc => ({\n id: doc.id,\n name: doc.name,\n isAdmin: doc.isAdmin ?? false,\n defaultPermissions: doc.defaultPermissions ?? null,\n collectionPermissions: doc.collectionPermissions ?? null\n }));\n }\n\n async createRole(data: CreateRoleData): Promise<RoleData> {\n const doc = {\n _id: data.id,\n id: data.id,\n name: data.name,\n isAdmin: data.isAdmin ?? false,\n defaultPermissions: data.defaultPermissions ?? null,\n collectionPermissions: data.collectionPermissions ?? null\n };\n await this.collection.insertOne(doc);\n return { ...doc } as RoleData;\n }\n\n async updateRole(id: string, data: Partial<Omit<RoleData, \"id\">>): Promise<RoleData | null> {\n await this.collection.updateOne({ id }, { $set: data });\n return this.getRoleById(id);\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.collection.deleteOne({ id });\n await this.db.collection(\"rebase_user_roles\").deleteMany({ roleId: id });\n }\n}\n\nexport class MongoRefreshTokenService {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_refresh_tokens\");\n }\n\n private toInfo(doc: MongoDoc): RefreshTokenInfo {\n return {\n id: doc.id,\n uid: doc.uid,\n tokenHash: doc.tokenHash,\n expiresAt: new Date(doc.expiresAt),\n createdAt: new Date(doc.createdAt),\n userAgent: doc.userAgent,\n ipAddress: doc.ipAddress,\n sessionId: doc.sessionId,\n rotatedAt: doc.rotatedAt ? new Date(doc.rotatedAt) : null,\n revoked: Boolean(doc.revoked),\n sessionStartedAt: new Date(doc.sessionStartedAt || doc.createdAt)\n };\n }\n\n async createToken(\n uid: string,\n tokenHash: string,\n expiresAt: Date,\n userAgent?: string,\n ipAddress?: string,\n session?: RefreshTokenSession\n ): Promise<void> {\n const safeUserAgent = userAgent || \"\";\n const safeIpAddress = ipAddress || \"\";\n\n // No deleteMany first. Tokens of one sign-in accumulate under a shared\n // sessionId and are pruned once nobody can still be holding them —\n // evicting by (uid, userAgent, ipAddress) is what used to sign out a\n // second browser profile behind the same address.\n const now = new Date();\n await this.collection.insertOne({\n _id: new ObjectId().toString(),\n id: new ObjectId().toString(),\n uid,\n tokenHash,\n expiresAt,\n createdAt: now,\n userAgent: safeUserAgent,\n ipAddress: safeIpAddress,\n sessionId: session?.id ?? new ObjectId().toString(),\n sessionStartedAt: session?.startedAt ?? now,\n rotatedAt: null,\n revoked: false\n });\n }\n\n async findByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n const doc = await this.collection.findOne({ tokenHash });\n return doc ? this.toInfo(doc) : null;\n }\n\n /** Superseded, not gone — see the Postgres service for why that matters. */\n async markRotated(tokenHash: string): Promise<void> {\n await this.collection.updateOne({ tokenHash }, { $set: { rotatedAt: new Date() } });\n }\n\n async revokeSession(sessionId: string): Promise<void> {\n await this.collection.updateMany(\n { sessionId },\n { $set: { revoked: true, rotatedAt: new Date() } }\n );\n }\n\n async prune(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.collection.deleteMany({\n uid,\n $or: [\n { expiresAt: { $lt: new Date() } },\n { sessionId, rotatedAt: { $ne: null, $lt: supersededBefore } }\n ]\n });\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n const user = await this.db.collection<MongoDoc>(\"rebase_users\").findOne({ id: uid });\n return user?.tokensValidAfter ? new Date(user.tokensValidAfter) : null;\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.db.collection<MongoDoc>(\"rebase_users\")\n .updateOne({ id: uid }, { $set: { tokensValidAfter: at } });\n }\n\n async deleteByHash(tokenHash: string): Promise<void> {\n await this.collection.deleteOne({ tokenHash });\n }\n\n async deleteAllForUser(uid: string): Promise<void> {\n await this.collection.deleteMany({ uid });\n }\n\n async listForUser(uid: string): Promise<RefreshTokenInfo[]> {\n const docs = await this.collection.find({ uid }).sort({ createdAt: 1 }).toArray();\n return docs.map(doc => this.toInfo(doc));\n }\n\n async deleteById(id: string, uid: string): Promise<void> {\n await this.collection.deleteOne({ id,\nuid });\n }\n}\n\nexport class MongoPasswordResetTokenService {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_password_reset_tokens\");\n }\n\n async createToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.collection.deleteMany({ uid,\nusedAt: null });\n\n await this.collection.insertOne({\n _id: new ObjectId().toString(),\n uid,\n tokenHash,\n expiresAt,\n usedAt: null\n });\n }\n\n async findValidByHash(tokenHash: string): Promise<{ uid: string; expiresAt: Date } | null> {\n const doc = await this.collection.findOne({\n tokenHash,\n usedAt: null,\n expiresAt: { $gt: new Date() }\n });\n\n if (!doc) return null;\n\n return {\n uid: doc.uid,\n expiresAt: new Date(doc.expiresAt)\n };\n }\n\n async markAsUsed(tokenHash: string): Promise<void> {\n await this.collection.updateOne(\n { tokenHash },\n { $set: { usedAt: new Date() } }\n );\n }\n\n async deleteAllForUser(uid: string): Promise<void> {\n await this.collection.deleteMany({ uid });\n }\n\n async deleteExpired(): Promise<void> {\n await this.collection.deleteMany({ expiresAt: { $lt: new Date() } });\n }\n}\n\nexport class MongoTokenRepository implements TokenRepository {\n private refreshTokenService: MongoRefreshTokenService;\n private passwordResetTokenService: MongoPasswordResetTokenService;\n\n constructor(private db: Db) {\n this.refreshTokenService = new MongoRefreshTokenService(db);\n this.passwordResetTokenService = new MongoPasswordResetTokenService(db);\n }\n\n async createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void> {\n await this.refreshTokenService.createToken(uid, tokenHash, expiresAt, userAgent, ipAddress, session);\n }\n\n async markRefreshTokenRotated(tokenHash: string): Promise<void> {\n await this.refreshTokenService.markRotated(tokenHash);\n }\n\n async revokeRefreshTokenSession(sessionId: string): Promise<void> {\n await this.refreshTokenService.revokeSession(sessionId);\n }\n\n async pruneRefreshTokens(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.refreshTokenService.prune(uid, sessionId, supersededBefore);\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n return this.refreshTokenService.getTokensValidAfter(uid);\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.refreshTokenService.setTokensValidAfter(uid, at);\n }\n\n async findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n return this.refreshTokenService.findByHash(tokenHash);\n }\n\n async deleteRefreshToken(tokenHash: string): Promise<void> {\n await this.refreshTokenService.deleteByHash(tokenHash);\n }\n\n async deleteAllRefreshTokensForUser(uid: string): Promise<void> {\n await this.refreshTokenService.deleteAllForUser(uid);\n }\n\n async listRefreshTokensForUser(uid: string): Promise<RefreshTokenInfo[]> {\n return this.refreshTokenService.listForUser(uid);\n }\n\n async deleteRefreshTokenById(id: string, uid: string): Promise<void> {\n await this.refreshTokenService.deleteById(id, uid);\n }\n\n async createPasswordResetToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.passwordResetTokenService.createToken(uid, tokenHash, expiresAt);\n }\n\n async findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null> {\n return this.passwordResetTokenService.findValidByHash(tokenHash);\n }\n\n async markPasswordResetTokenUsed(tokenHash: string): Promise<void> {\n await this.passwordResetTokenService.markAsUsed(tokenHash);\n }\n\n async deleteAllPasswordResetTokensForUser(uid: string): Promise<void> {\n await this.passwordResetTokenService.deleteAllForUser(uid);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.passwordResetTokenService.deleteExpired();\n }\n\n // Magic link token operations\n\n async createMagicLinkToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n const col = this.db.collection(\"magic_link_tokens\");\n await col.deleteMany({ uid, usedAt: null });\n await col.insertOne({ uid, tokenHash, expiresAt, usedAt: null, createdAt: new Date() });\n }\n\n async findValidMagicLinkToken(tokenHash: string): Promise<MagicLinkTokenInfo | null> {\n const col = this.db.collection(\"magic_link_tokens\");\n const doc = await col.findOne({ tokenHash, usedAt: null, expiresAt: { $gt: new Date() } });\n if (!doc) return null;\n return { uid: doc.uid as string, expiresAt: doc.expiresAt as Date };\n }\n\n async markMagicLinkTokenUsed(tokenHash: string): Promise<void> {\n const col = this.db.collection(\"magic_link_tokens\");\n await col.updateOne({ tokenHash }, { $set: { usedAt: new Date() } });\n }\n}\n\nexport class MongoAuthRepository implements AuthRepository {\n private userService: MongoUserService;\n private roleService: MongoRoleService;\n private tokenRepository: MongoTokenRepository;\n\n constructor(private db: Db) {\n this.userService = new MongoUserService(db);\n this.roleService = new MongoRoleService(db);\n this.tokenRepository = new MongoTokenRepository(db);\n }\n\n async createUser(data: CreateUserData): Promise<UserData> {\n return this.userService.createUser(data);\n }\n\n async getUserById(id: string): Promise<UserData | null> {\n return this.userService.getUserById(id);\n }\n\n async getUserByEmail(email: string): Promise<UserData | null> {\n return this.userService.getUserByEmail(email);\n }\n\n async getUserByIdentity(provider: string, providerId: string): Promise<UserData | null> {\n return this.userService.getUserByIdentity(provider, providerId);\n }\n\n async getUserIdentities(uid: string): Promise<UserIdentityData[]> {\n return this.userService.getUserIdentities(uid);\n }\n\n async linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n return this.userService.linkUserIdentity(uid, provider, providerId, profileData);\n }\n\n async updateUser(id: string, data: Partial<Omit<CreateUserData, \"id\">>): Promise<UserData | null> {\n return this.userService.updateUser(id, data);\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.userService.deleteUser(id);\n }\n\n async listUsers(): Promise<UserData[]> {\n return this.userService.listUsers();\n }\n\n async listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult> {\n return this.userService.listUsersPaginated(options);\n }\n\n async updatePassword(id: string, passwordHash: string): Promise<void> {\n await this.userService.updatePassword(id, passwordHash);\n }\n\n async setEmailVerified(id: string, verified: boolean): Promise<void> {\n await this.userService.setEmailVerified(id, verified);\n }\n\n async setVerificationToken(id: string, token: string | null): Promise<void> {\n await this.userService.setVerificationToken(id, token);\n }\n\n async getUserByVerificationToken(token: string): Promise<UserData | null> {\n return this.userService.getUserByVerificationToken(token);\n }\n\n async getUserRoles(uid: string): Promise<RoleData[]> {\n return this.userService.getUserRoles(uid);\n }\n\n async getUserRoleIds(uid: string): Promise<string[]> {\n return this.userService.getUserRoleIds(uid);\n }\n\n async setUserRoles(uid: string, roleIds: string[]): Promise<void> {\n await this.userService.setUserRoles(uid, roleIds);\n }\n\n async assignDefaultRole(uid: string, roleId: string): Promise<void> {\n await this.userService.assignDefaultRole(uid, roleId);\n }\n\n async getUserWithRoles(uid: string): Promise<{ user: UserData; roles: RoleData[] } | null> {\n return this.userService.getUserWithRoles(uid);\n }\n\n async getRoleById(id: string): Promise<RoleData | null> {\n return this.roleService.getRoleById(id);\n }\n\n async listRoles(): Promise<RoleData[]> {\n return this.roleService.listRoles();\n }\n\n async createRole(data: CreateRoleData): Promise<RoleData> {\n return this.roleService.createRole(data);\n }\n\n async updateRole(id: string, data: Partial<Omit<RoleData, \"id\">>): Promise<RoleData | null> {\n return this.roleService.updateRole(id, data);\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.roleService.deleteRole(id);\n }\n\n async createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void> {\n await this.tokenRepository.createRefreshToken(uid, tokenHash, expiresAt, userAgent, ipAddress, session);\n }\n\n async markRefreshTokenRotated(tokenHash: string): Promise<void> {\n await this.tokenRepository.markRefreshTokenRotated(tokenHash);\n }\n\n async revokeRefreshTokenSession(sessionId: string): Promise<void> {\n await this.tokenRepository.revokeRefreshTokenSession(sessionId);\n }\n\n async pruneRefreshTokens(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.tokenRepository.pruneRefreshTokens(uid, sessionId, supersededBefore);\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n return this.tokenRepository.getTokensValidAfter(uid);\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.tokenRepository.setTokensValidAfter(uid, at);\n }\n\n async findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n return this.tokenRepository.findRefreshTokenByHash(tokenHash);\n }\n\n async deleteRefreshToken(tokenHash: string): Promise<void> {\n await this.tokenRepository.deleteRefreshToken(tokenHash);\n }\n\n async deleteAllRefreshTokensForUser(uid: string): Promise<void> {\n await this.tokenRepository.deleteAllRefreshTokensForUser(uid);\n }\n\n async listRefreshTokensForUser(uid: string): Promise<RefreshTokenInfo[]> {\n return this.tokenRepository.listRefreshTokensForUser(uid);\n }\n\n async deleteRefreshTokenById(id: string, uid: string): Promise<void> {\n await this.tokenRepository.deleteRefreshTokenById(id, uid);\n }\n\n async createPasswordResetToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.tokenRepository.createPasswordResetToken(uid, tokenHash, expiresAt);\n }\n\n async findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null> {\n return this.tokenRepository.findValidPasswordResetToken(tokenHash);\n }\n\n async markPasswordResetTokenUsed(tokenHash: string): Promise<void> {\n await this.tokenRepository.markPasswordResetTokenUsed(tokenHash);\n }\n\n async deleteAllPasswordResetTokensForUser(uid: string): Promise<void> {\n await this.tokenRepository.deleteAllPasswordResetTokensForUser(uid);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.tokenRepository.deleteExpiredTokens();\n }\n\n // Magic link token operations\n\n async createMagicLinkToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.tokenRepository.createMagicLinkToken(uid, tokenHash, expiresAt);\n }\n\n async findValidMagicLinkToken(tokenHash: string): Promise<MagicLinkTokenInfo | null> {\n return this.tokenRepository.findValidMagicLinkToken(tokenHash);\n }\n\n async markMagicLinkTokenUsed(tokenHash: string): Promise<void> {\n await this.tokenRepository.markMagicLinkTokenUsed(tokenHash);\n }\n\n // MFA Repository Stub\n async createMfaFactor(uid: string, factorType: \"totp\", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async getMfaFactors(uid: string): Promise<MfaFactor[]> {\n return [];\n }\n async getMfaFactorById(factorId: string): Promise<(MfaFactor & { secretEncrypted: string }) | null> {\n return null;\n }\n async verifyMfaFactor(factorId: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async deleteMfaFactor(factorId: string, uid: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async createMfaChallenge(factorId: string, ipAddress?: string): Promise<MfaChallengeInfo> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async getMfaChallengeById(challengeId: string): Promise<MfaChallengeInfo | null> {\n return null;\n }\n async verifyMfaChallenge(challengeId: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async createRecoveryCodes(uid: string, codeHashes: string[]): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async useRecoveryCode(uid: string, codeHash: string): Promise<boolean> {\n return false;\n }\n async getUnusedRecoveryCodeCount(uid: string): Promise<number> {\n return 0;\n }\n async deleteAllRecoveryCodes(uid: string): Promise<void> {\n // No-op\n }\n async hasVerifiedMfaFactors(uid: string): Promise<boolean> {\n return false;\n }\n}\n","import { Db, MongoClient } from \"mongodb\";\nimport type {\n BackendBootstrapper,\n InitializedDriver,\n BootstrappedAuth,\n DatabaseAdmin,\n HistoryConfig,\n RealtimeProvider,\n DataDriver,\n CollectionConfig\n} from \"@rebasepro/types\";\nimport { MongoDriver } from \"./services/MongoDriver\";\nimport { MongoRealtimeService } from \"./services/MongoRealtimeService\";\nimport { MongoCollectionRegistry } from \"./factory\";\nimport { MongoAuthRepository, MongoUserService, MongoRoleService } from \"./auth/services\";\nimport { logger } from \"@rebasepro/server\";\n\nexport interface MongoDriverConfig {\n connection: Db;\n client: MongoClient;\n}\n\nexport interface MongoDriverInternals {\n db: Db;\n client: MongoClient;\n registry: MongoCollectionRegistry;\n realtimeService: MongoRealtimeService;\n driver: MongoDriver;\n}\n\n/** Shape of the config object passed to `initializeDriver` by the coordinator. */\ninterface DriverInitConfig {\n collections?: CollectionConfig[];\n}\n\n/** Shape of the auth config passed to `initializeAuth`. */\ninterface AuthInitConfig {\n email?: import(\"@rebasepro/server\").EmailConfig;\n}\n\n\n\nexport function createMongoBootstrapper(mongoConfig: MongoDriverConfig): BackendBootstrapper {\n // Cached admin object, set during getAdmin() and used by initializeWebsockets\n let cachedAdmin: DatabaseAdmin | undefined;\n\n return {\n type: \"mongodb\",\n\n async initializeDriver(config: unknown): Promise<InitializedDriver> {\n const { collections } = config as DriverInitConfig;\n\n const registry = new MongoCollectionRegistry();\n if (collections) {\n collections.forEach(collection => registry.register(collection));\n }\n\n const db = mongoConfig.connection;\n const client = mongoConfig.client;\n\n // Verify connection\n try {\n await db.command({ ping: 1 });\n } catch (err) {\n logger.error(\"❌ Failed to connect to MongoDB\", { error: err });\n }\n\n const realtimeService = new MongoRealtimeService(db);\n const driver = new MongoDriver(db, realtimeService, undefined, registry);\n\n const internals: MongoDriverInternals = {\n db,\n client,\n registry,\n realtimeService,\n driver\n };\n\n return {\n driver,\n realtimeProvider: realtimeService,\n collectionRegistry: registry,\n internals\n };\n },\n\n async initializeAuth(config: unknown, driverResult: InitializedDriver): Promise<BootstrappedAuth | undefined> {\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const { ensureAuthCollectionsExist } = await import(\"./auth/ensure-collections\");\n await ensureAuthCollectionsExist(db);\n\n const { createEmailService } = await import(\"@rebasepro/server\");\n const authConfig = config as AuthInitConfig | undefined;\n let emailService: unknown;\n if (authConfig?.email) {\n emailService = createEmailService(authConfig.email);\n }\n\n const userService = new MongoUserService(db);\n const roleService = new MongoRoleService(db);\n const authRepository = new MongoAuthRepository(db);\n\n return {\n userService,\n roleService,\n authRepository,\n emailService\n };\n },\n\n async initializeHistory(config: HistoryConfig, driverResult: InitializedDriver): Promise<{ historyService: unknown } | undefined> {\n if (!config) return undefined;\n\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const { ensureHistoryCollectionExists } = await import(\"./history/ensure-history-collection\");\n await ensureHistoryCollectionExists(db);\n\n const { MongoHistoryService } = await import(\"./services/MongoHistoryService\");\n\n const retention = typeof config === \"object\" ? config.retention : undefined;\n const historyService = new MongoHistoryService(db, retention ? { ttlDays: retention } : undefined);\n\n return { historyService };\n },\n\n async initializeRealtime(_config: unknown, driverResult: InitializedDriver): Promise<RealtimeProvider | undefined> {\n const internals = driverResult.internals as MongoDriverInternals;\n return internals.realtimeService;\n },\n\n getAdmin(driverResult: InitializedDriver): DatabaseAdmin | undefined {\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const admin: DatabaseAdmin = {\n async executeAggregate(pipeline: Record<string, unknown>[]) {\n const firstStage = pipeline[0];\n const collName = (firstStage as { $from?: string })?.$from ?? \"__admin__\";\n const cursor = db.collection(collName).aggregate(pipeline);\n return await cursor.toArray() as Record<string, unknown>[];\n },\n async fetchCollectionStats(collectionName: string) {\n const stats = await db.command({ collStats: collectionName }) as { count: number; size: number };\n return { count: stats.count,\nsizeBytes: stats.size };\n },\n async fetchUnmappedTables(mappedPaths?: string[]) {\n const allCollections = await db.listCollections().toArray();\n const names = allCollections.map(c => c.name).filter(n => !n.startsWith(\"system.\"));\n if (!mappedPaths || mappedPaths.length === 0) return names;\n const mappedSet = new Set(mappedPaths.map(p => p.toLowerCase()));\n return names.filter(n => !mappedSet.has(n.toLowerCase()));\n },\n async fetchTableMetadata(collectionName: string) {\n const sample = await db.collection(collectionName).findOne();\n if (!sample) return { columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n const columns = Object.entries(sample).map(([key, value]) => ({\n column_name: key,\n data_type: typeof value,\n udt_name: typeof value,\n is_nullable: \"YES\",\n column_default: null,\n character_maximum_length: null\n }));\n return { columns,\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n }\n };\n\n cachedAdmin = admin;\n return admin;\n },\n\n mountRoutes() {},\n\n async initializeWebsockets(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown): Promise<void> {\n const { createMongoWebSocket } = await import(\"./websocket\");\n createMongoWebSocket(\n server as import(\"http\").Server,\n realtimeService as MongoRealtimeService,\n driver as MongoDriver,\n config as Record<string, unknown> | undefined,\n cachedAdmin\n );\n }\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","names":[],"sources":["../src/connection.ts","../src/db/MongoConditionBuilder.ts","../src/db/MongoDataService.ts","../src/services/MongoRealtimeService.ts","../src/services/MongoHistoryService.ts","../src/services/MongoDriver.ts","../src/factory.ts","../src/auth/services.ts","../src/MongoBootstrapper.ts"],"sourcesContent":["/**\n * MongoDB Connection\n *\n * Wraps MongoDB connection to implement the DatabaseConnection interface.\n */\n\nimport { Db, MongoClient } from \"mongodb\";\nimport { DatabaseConnection } from \"@rebasepro/types\";\n\n/**\n * MongoDB database connection wrapper that implements DatabaseConnection interface.\n */\nexport class MongoDBConnection implements DatabaseConnection {\n readonly type = \"mongodb\";\n\n constructor(\n public readonly db: Db,\n public readonly client: MongoClient\n ) { }\n\n get isConnected(): boolean {\n // MongoClient doesn't have a direct isConnected property in v6+\n // We check if the client topology is connected\n try {\n const clientInternal = this.client as unknown as Record<string, { isConnected?: () => boolean } | undefined>;\n return clientInternal.topology?.isConnected?.() ?? false;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n await this.client.close();\n }\n}\n\n/**\n * Create a MongoDB database connection from a connection string.\n *\n * @param connectionString - MongoDB connection string (e.g., mongodb://localhost:27017)\n * @param databaseName - Name of the database to use\n * @returns Promise resolving to MongoDBConnection\n *\n * @example\n * ```typescript\n * const connection = await createMongoDBConnection(\n * \"mongodb://localhost:27017\",\n * \"my_database\"\n * );\n * ```\n */\nexport async function createMongoDBConnection(\n connectionString: string,\n databaseName: string\n): Promise<MongoDBConnection> {\n const client = new MongoClient(connectionString);\n await client.connect();\n const db = client.db(databaseName);\n return new MongoDBConnection(db, client);\n}\n","/**\n * MongoDB Condition Builder\n *\n * Translates Rebase filter conditions to MongoDB query operators.\n */\n\nimport { FilterValues, WhereFilterOp } from \"@rebasepro/types\";\nimport { Filter, Document } from \"mongodb\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * Mapping from Rebase filter operators to MongoDB query operators\n */\nconst REBASE_TO_MONGO_OP: Partial<Record<WhereFilterOp, string>> = {\n \"<\": \"$lt\",\n \"<=\": \"$lte\",\n \"==\": \"$eq\",\n \"!=\": \"$ne\",\n \">=\": \"$gte\",\n \">\": \"$gt\",\n \"array-contains\": \"$elemMatch\",\n \"array-contains-any\": \"$in\",\n \"in\": \"$in\",\n \"not-in\": \"$nin\"\n};\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Translate a SQL LIKE/ILIKE pattern into an anchored regular expression.\n * `%` matches any sequence of characters, `_` matches a single character;\n * every other character is matched literally.\n */\nfunction likePatternToRegExp(pattern: string, caseInsensitive: boolean): RegExp {\n let body = \"\";\n for (const ch of String(pattern)) {\n if (ch === \"%\") body += \".*\";\n else if (ch === \"_\") body += \".\";\n else body += escapeRegExp(ch);\n }\n return new RegExp(`^${body}$`, caseInsensitive ? \"i\" : \"\");\n}\n\n/**\n * MongoDB Condition Builder\n *\n * Provides static methods to translate Rebase filter conditions\n * to MongoDB query filters.\n */\nexport class MongoConditionBuilder {\n /**\n * Build MongoDB filter conditions from Rebase FilterValues\n *\n * @param filter - Rebase filter values\n * @returns Array of MongoDB filter objects\n */\n static buildFilterConditions<M extends Record<string, any>>(\n filter: FilterValues<Extract<keyof M, string>>\n ): Filter<Document>[] {\n if (!filter) return [];\n\n const conditions: Filter<Document>[] = [];\n\n for (const [field, filterParam] of Object.entries(filter)) {\n if (!filterParam) continue;\n\n const [op, value] = filterParam as [WhereFilterOp, any];\n\n // Null-testing operators ignore their value.\n if (op === \"is-null\") {\n conditions.push({ [field]: { $eq: null } });\n continue;\n }\n if (op === \"is-not-null\") {\n conditions.push({ [field]: { $ne: null } });\n continue;\n }\n\n // Pattern matching → regular expressions.\n if (op === \"like\" || op === \"ilike\" || op === \"not-like\" || op === \"not-ilike\") {\n const caseInsensitive = op === \"ilike\" || op === \"not-ilike\";\n const regex = likePatternToRegExp(value, caseInsensitive);\n const negated = op === \"not-like\" || op === \"not-ilike\";\n conditions.push({\n [field]: negated ? { $not: regex } : { $regex: regex }\n });\n continue;\n }\n\n const mongoOp = REBASE_TO_MONGO_OP[op];\n\n if (!mongoOp) {\n logger.warn(`Unsupported filter operator: ${op}`);\n continue;\n }\n\n // Handle array-contains specially\n if (op === \"array-contains\") {\n conditions.push({\n [field]: { $elemMatch: { $eq: value } }\n });\n } else {\n conditions.push({\n [field]: { [mongoOp]: value }\n });\n }\n }\n\n return conditions;\n }\n\n /**\n * Build search conditions for text search\n *\n * @param searchString - Text to search for\n * @param properties - Properties to search in\n * @returns Array of MongoDB filter objects for text search\n */\n static buildSearchConditions(\n searchString: string,\n properties: Record<string, any>\n ): Filter<Document>[] {\n if (!searchString) return [];\n\n // Build regex conditions for each searchable string property\n const orConditions: Filter<Document>[] = [];\n const escapedSearch = escapeRegExp(searchString);\n const searchRegex = new RegExp(escapedSearch, \"i\");\n\n for (const [key, prop] of Object.entries(properties)) {\n // Only search in string-type properties\n if (prop?.dataType === \"string\" || typeof prop === \"string\") {\n orConditions.push({\n [key]: { $regex: searchRegex }\n });\n }\n }\n\n // If no properties to search, use MongoDB text search\n if (orConditions.length === 0) {\n return [{ $text: { $search: searchString } }];\n }\n\n return orConditions;\n }\n\n /**\n * Combine multiple conditions with AND operator\n *\n * @param conditions - Array of filter conditions\n * @returns Combined filter or undefined if empty\n */\n static combineConditionsWithAnd(conditions: Filter<Document>[]): Filter<Document> | undefined {\n if (conditions.length === 0) return undefined;\n if (conditions.length === 1) return conditions[0];\n return { $and: conditions };\n }\n\n /**\n * Combine multiple conditions with OR operator\n *\n * @param conditions - Array of filter conditions\n * @returns Combined filter or undefined if empty\n */\n static combineConditionsWithOr(conditions: Filter<Document>[]): Filter<Document> | undefined {\n if (conditions.length === 0) return undefined;\n if (conditions.length === 1) return conditions[0];\n return { $or: conditions };\n }\n\n /**\n * Build a complete MongoDB query from Rebase options\n *\n * @param options - Rebase fetch options\n * @returns MongoDB filter object\n */\n static buildQuery<M extends Record<string, any>>(options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n searchString?: string;\n properties?: Record<string, any>;\n }): Filter<Document> {\n const conditions: Filter<Document>[] = [];\n\n // Add filter conditions\n if (options.filter) {\n const filterConditions = this.buildFilterConditions<M>(options.filter);\n conditions.push(...filterConditions);\n }\n\n // Add search conditions\n if (options.searchString && options.properties) {\n const searchConditions = this.buildSearchConditions(\n options.searchString,\n options.properties\n );\n if (searchConditions.length > 0) {\n // Search conditions are OR'd together\n const searchFilter = this.combineConditionsWithOr(searchConditions);\n if (searchFilter) {\n conditions.push(searchFilter);\n }\n }\n }\n\n return this.combineConditionsWithAnd(conditions) ?? {};\n }\n\n /**\n * Build MongoDB sort options from Rebase options\n *\n * @param orderBy - Field to order by\n * @param order - Sort direction\n * @returns MongoDB sort object\n */\n static buildSort(\n orderBy?: string,\n order?: \"asc\" | \"desc\"\n ): Record<string, 1 | -1> | undefined {\n if (!orderBy) return undefined;\n return { [orderBy]: order === \"desc\" ? -1 : 1 };\n }\n}\n","/**\n * MongoDB Row Service\n *\n * Implements DataRepository interface for MongoDB.\n * Provides all CRUD operations for rows.\n */\n\nimport { Db, ObjectId, Collection, Document, FindOptions, Filter } from \"mongodb\";\nimport { FilterValues, DataRepository, CollectionConfig, EntityReference } from \"@rebasepro/types\";\nimport { MongoConditionBuilder } from \"./MongoConditionBuilder\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * MongoDB Row Service\n *\n * Implements the DataRepository interface for MongoDB.\n * Provides all CRUD operations for rows stored in MongoDB collections.\n */\nexport class MongoDataService implements DataRepository {\n constructor(private db: Db) { }\n\n /**\n * Get a MongoDB collection by its path\n */\n private getCollection(collectionPath: string): Collection<Document> {\n // Handle nested paths (e.g., \"posts/123/comments\" -> \"posts_123_comments\")\n const collectionName = collectionPath.replace(/\\//g, \"_\");\n return this.db.collection(collectionName);\n }\n\n /**\n * Convert a string ID to ObjectId if it's a valid ObjectId string\n */\n private toObjectId(id: string | number): ObjectId | string | number {\n if (typeof id === \"string\" && ObjectId.isValid(id) && id.length === 24) {\n return new ObjectId(id);\n }\n return id;\n }\n\n /**\n * Convert a MongoDB document to a flat row (`{ id, ...fields }`)\n */\n private documentToRow(doc: Document): Record<string, unknown> {\n const { _id, ...values } = doc;\n return {\n ...this.convertFromMongoValues(values),\n // Spread the canonical id last so it wins over a literal `id` field\n id: _id.toString()\n };\n }\n\n /**\n * Convert values from MongoDB format to Rebase format\n */\n private convertFromMongoValues(values: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(values)) {\n result[key] = this.convertFromMongoValue(value);\n }\n\n return result;\n }\n\n /**\n * Convert a single value from MongoDB format\n */\n private convertFromMongoValue(value: any): any {\n if (value === null || value === undefined) return value;\n\n // Handle ObjectId\n if (value instanceof ObjectId) {\n return value.toString();\n }\n\n // Handle Date\n if (value instanceof Date) {\n return value;\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map(v => this.convertFromMongoValue(v));\n }\n\n // Handle stored EntityReference. New writes are tagged with the\n // `__type: \"reference\"` sentinel (see convertToMongoValue), which is\n // unambiguous. We also accept the legacy shape — an object whose ONLY\n // keys are `id` and `path` — so references written before the sentinel\n // existed still decode. We deliberately do NOT treat any object that\n // merely *contains* `id` and `path` as a reference, because that\n // silently rewrites ordinary embedded sub-documents.\n if (typeof value === \"object\") {\n const keys = Object.keys(value);\n const isTagged = value.__type === \"reference\" && \"id\" in value && \"path\" in value;\n const isLegacy = keys.length === 2 && keys.includes(\"id\") && keys.includes(\"path\");\n if (isTagged || isLegacy) {\n return new EntityReference({\n id: value.id instanceof ObjectId ? value.id.toString() : String(value.id),\n path: value.path,\n driver: value.driver,\n databaseId: value.databaseId\n });\n }\n }\n\n // Handle nested objects\n if (typeof value === \"object\") {\n return this.convertFromMongoValues(value);\n }\n\n return value;\n }\n\n /**\n * Convert values to MongoDB format for storage\n */\n private convertToMongoValues(values: Record<string, any>): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(values)) {\n result[key] = this.convertToMongoValue(value);\n }\n\n return result;\n }\n\n /**\n * Convert a single value to MongoDB format\n */\n private convertToMongoValue(value: any): any {\n if (value === null || value === undefined) return value;\n\n // Handle EntityReference. Persist with a `__type: \"reference\"` sentinel\n // so it round-trips unambiguously, and preserve `driver`/`databaseId`\n // so cross-datasource pointers don't lose their target on write.\n if (typeof value === \"object\" && value.isEntityReference?.()) {\n const ref: Record<string, unknown> = {\n __type: \"reference\",\n id: ObjectId.isValid(value.id) ? new ObjectId(value.id) : value.id,\n path: value.path\n };\n if (value.driver !== undefined) ref.driver = value.driver;\n if (value.databaseId !== undefined) ref.databaseId = value.databaseId;\n return ref;\n }\n\n // Handle Date\n if (value instanceof Date) {\n return value;\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n return value.map(v => this.convertToMongoValue(v));\n }\n\n // Handle nested objects\n if (typeof value === \"object\") {\n return this.convertToMongoValues(value);\n }\n\n return value;\n }\n\n // =============================================================\n // DataRepository Implementation\n // =============================================================\n\n /**\n * Fetch a single row by ID\n */\n async fetchOne<M extends Record<string, any>>(\n collectionPath: string,\n id: string | number,\n _databaseId?: string\n ): Promise<Record<string, unknown> | undefined> {\n const collection = this.getCollection(collectionPath);\n const objectId = this.toObjectId(id);\n\n const doc = await collection.findOne({ _id: objectId } as Filter<Document>);\n\n if (!doc) return undefined;\n\n return this.documentToRow(doc);\n }\n\n /**\n * Fetch a collection of rows with optional filtering, ordering, and pagination\n */\n async fetchCollection<M extends Record<string, any>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: any;\n searchString?: string;\n databaseId?: string;\n collection?: CollectionConfig;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<Record<string, unknown>[]> {\n const collection = this.getCollection(collectionPath);\n\n // Build query\n const query = options.rawQuery ?? MongoConditionBuilder.buildQuery<M>({\n filter: options.filter,\n searchString: options.searchString,\n properties: options.collection?.properties ?? {}\n });\n\n // Build find options\n const findOptions: FindOptions = {};\n\n // Apply sorting\n const sort = MongoConditionBuilder.buildSort(options.orderBy, options.order);\n if (sort) {\n findOptions.sort = sort;\n }\n\n // Apply limit\n if (options.limit) {\n findOptions.limit = options.limit;\n }\n\n // Apply pagination (skip-based for now, cursor-based would be better)\n if (options.startAfter !== undefined) {\n findOptions.skip = Number(options.startAfter);\n }\n\n const docs = await collection.find(query, findOptions).toArray();\n\n return docs.map((doc: Document) => this.documentToRow(doc));\n }\n\n /**\n * Search rows by text\n */\n async searchRows<M extends Record<string, any>>(\n collectionPath: string,\n searchString: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n databaseId?: string;\n collection?: CollectionConfig;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<Record<string, unknown>[]> {\n return this.fetchCollection<M>(collectionPath, {\n ...options,\n searchString\n });\n }\n\n /**\n * Count rows in a collection\n */\n async count<M extends Record<string, any>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n databaseId?: string;\n rawQuery?: Filter<Document>;\n } = {}\n ): Promise<number> {\n const collection = this.getCollection(collectionPath);\n\n const query = options.rawQuery ?? (options.filter\n ? MongoConditionBuilder.buildQuery<M>({ filter: options.filter })\n : {});\n\n return collection.countDocuments(query);\n }\n\n /**\n * Save an row (create or update)\n */\n async save<M extends Record<string, any>>(\n collectionPath: string,\n values: Partial<M>,\n id?: string | number,\n _databaseId?: string\n ): Promise<Record<string, unknown>> {\n const collection = this.getCollection(collectionPath);\n const mongoValues = this.convertToMongoValues(values as Record<string, any>);\n\n if (id) {\n // Update existing row\n const objectId = this.toObjectId(id);\n await collection.updateOne(\n { _id: objectId } as Filter<Document>,\n { $set: mongoValues },\n { upsert: true }\n );\n\n return {\n ...values,\n id: id.toString()\n };\n } else {\n // Create new row\n const newId = new ObjectId();\n await collection.insertOne({\n _id: newId,\n ...mongoValues\n });\n\n return {\n ...values,\n id: newId.toString()\n };\n }\n }\n\n /**\n * Delete an row by ID\n */\n async delete(\n collectionPath: string,\n id: string | number,\n _databaseId?: string\n ): Promise<void> {\n const collection = this.getCollection(collectionPath);\n const objectId = this.toObjectId(id);\n\n const result = await collection.deleteOne({ _id: objectId } as Filter<Document>);\n\n if (result.deletedCount === 0) {\n logger.warn(`Row ${id} not found in collection ${collectionPath}`);\n }\n }\n\n /**\n * Check if a field value is unique in a collection\n */\n async checkUniqueField(\n collectionPath: string,\n fieldName: string,\n value: any,\n excludeEntityId?: string,\n _databaseId?: string\n ): Promise<boolean> {\n const collection = this.getCollection(collectionPath);\n\n const query: Filter<Document> = { [fieldName]: value };\n\n if (excludeEntityId) {\n const objectId = this.toObjectId(excludeEntityId);\n (query as Record<string, unknown>)._id = { $ne: objectId };\n }\n\n const count = await collection.countDocuments(query);\n return count === 0;\n }\n\n /**\n * Generate a new row ID\n */\n generateId(): string {\n return new ObjectId().toString();\n }\n}\n","/**\n * MongoDB Realtime Service\n *\n * Implements RealtimeProvider interface using MongoDB Change Streams.\n * Provides real-time subscriptions to collection and row changes.\n */\n\nimport { Db, ChangeStream, ChangeStreamDocument, Document, ObjectId } from \"mongodb\";\nimport {\n FilterValues,\n RealtimeProvider,\n CollectionSubscriptionConfig,\n SingleSubscriptionConfig,\n WebSocketMessage,\n User\n} from \"@rebasepro/types\";\nimport { WebSocket } from \"ws\";\nimport { MongoDataService } from \"../db/MongoDataService\";\n\nimport type { MongoDriver } from \"./MongoDriver\";\nimport { logger } from \"@rebasepro/server\";\n\ninterface Subscription {\n type: \"collection\" | \"single\";\n config: CollectionSubscriptionConfig | SingleSubscriptionConfig;\n changeStream?: ChangeStream;\n callback?: (data: any) => void;\n authContext?: { uid: string; roles: string[] };\n}\n\n/**\n * MongoDB Realtime Service\n *\n * Implements real-time subscriptions using MongoDB Change Streams.\n * Requires MongoDB replica set for change streams to work.\n */\nexport class MongoRealtimeService implements RealtimeProvider {\n private subscriptions = new Map<string, Subscription>();\n private clients = new Map<string, WebSocket>();\n private dataService: MongoDataService;\n private driver?: MongoDriver;\n\n constructor(private db: Db) {\n this.dataService = new MongoDataService(db);\n }\n\n setDataDriver(driver: MongoDriver) {\n this.driver = driver;\n }\n\n /**\n * Get the collection name from a path\n */\n private getCollectionName(path: string): string {\n return path.replace(/\\//g, \"_\");\n }\n\n /**\n * Subscribe to collection changes\n */\n subscribeToCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (rows: Record<string, unknown>[]) => void\n ): void {\n // Clean up existing subscription if any\n this.unsubscribe(subscriptionId);\n\n const collectionName = this.getCollectionName(config.path);\n const collection = this.db.collection(collectionName);\n\n // Build pipeline for change stream filtering\n const pipeline: Document[] = [];\n\n // Filter by operation types we care about\n pipeline.push({\n $match: {\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] }\n }\n });\n\n try {\n // Create change stream\n const changeStream = collection.watch(pipeline, {\n fullDocument: \"updateLookup\"\n });\n\n const subscription: Subscription = {\n type: \"collection\",\n config,\n changeStream,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyCollection(subscriptionId, config, callback);\n\n // Listen for changes\n changeStream.on(\"change\", async (change: ChangeStreamDocument) => {\n // Re-fetch the entire collection when any change happens\n // This is simpler and ensures consistent sorting/filtering\n await this.fetchAndNotifyCollection(subscriptionId, config, callback);\n });\n\n changeStream.on(\"error\", (error: Error) => {\n logger.error(`Change stream error for subscription ${subscriptionId}`, { error: error });\n });\n\n } catch (error) {\n // Change streams might not be available (e.g., standalone MongoDB)\n logger.warn(\"Change streams not available, falling back to polling\", { error: error });\n\n // Store subscription without change stream for manual notifications\n const subscription: Subscription = {\n type: \"collection\",\n config,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyCollection(subscriptionId, config, callback);\n }\n }\n\n /**\n * Fetch collection and notify callback\n */\n private async fetchAndNotifyCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (rows: Record<string, unknown>[]) => void\n ): Promise<void> {\n try {\n let rows;\n const registryCollection = this.driver?.registry?.getCollectionByPath(config.path);\n\n if (config.authContext && this.driver) {\n const mockUser = { uid: config.authContext.uid,\nroles: config.authContext.roles } as User;\n const authenticatedDriver = await this.driver.withAuth(mockUser);\n rows = await authenticatedDriver.fetchCollection({\n path: config.path,\n collection: registryCollection,\n filter: config.filter as FilterValues<string> | undefined,\n orderBy: config.orderBy,\n order: config.order,\n limit: config.limit,\n startAfter: config.startAfter,\n searchString: config.searchString\n });\n } else {\n rows = await this.dataService.fetchCollection(config.path, {\n filter: config.filter as FilterValues<string> | undefined,\n orderBy: config.orderBy,\n order: config.order,\n limit: config.limit,\n startAfter: config.startAfter,\n searchString: config.searchString,\n collection: registryCollection\n });\n }\n\n if (callback) {\n callback(rows);\n }\n } catch (error) {\n logger.error(`Error fetching collection for subscription ${subscriptionId}`, { error: error });\n }\n }\n\n /**\n * Subscribe to single row changes\n */\n subscribeToOne(\n subscriptionId: string,\n config: SingleSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (row: Record<string, unknown> | null) => void\n ): void {\n // Clean up existing subscription if any\n this.unsubscribe(subscriptionId);\n\n const collectionName = this.getCollectionName(config.path);\n const collection = this.db.collection(collectionName);\n\n // Build pipeline to watch specific document\n const id = typeof config.id === \"string\" && ObjectId.isValid(config.id)\n ? new ObjectId(config.id)\n : config.id;\n\n const pipeline: Document[] = [\n {\n $match: {\n \"documentKey._id\": id,\n operationType: { $in: [\"insert\", \"update\", \"replace\", \"delete\"] }\n }\n }\n ];\n\n try {\n const changeStream = collection.watch(pipeline, {\n fullDocument: \"updateLookup\"\n });\n\n const subscription: Subscription = {\n type: \"single\",\n config,\n changeStream,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyOne(subscriptionId, config, callback);\n\n // Listen for changes\n changeStream.on(\"change\", async (change: ChangeStreamDocument) => {\n if (change.operationType === \"delete\") {\n if (callback) {\n callback(null);\n }\n } else {\n await this.fetchAndNotifyOne(subscriptionId, config, callback);\n }\n });\n\n changeStream.on(\"error\", (error: Error) => {\n logger.error(`Change stream error for subscription ${subscriptionId}`, { error: error });\n });\n\n } catch (error) {\n logger.warn(\"Change streams not available, falling back to polling\", { error: error });\n\n const subscription: Subscription = {\n type: \"single\",\n config,\n callback,\n authContext: config.authContext\n };\n\n this.subscriptions.set(subscriptionId, subscription);\n\n // Fetch initial data\n this.fetchAndNotifyOne(subscriptionId, config, callback);\n }\n }\n\n /**\n * Fetch row and notify callback\n */\n private async fetchAndNotifyOne(\n subscriptionId: string,\n config: SingleSubscriptionConfig & { authContext?: { uid: string; roles: string[] } },\n callback?: (row: Record<string, unknown> | null) => void\n ): Promise<void> {\n try {\n let row;\n const registryCollection = this.driver?.registry?.getCollectionByPath(config.path);\n\n if (config.authContext && this.driver) {\n const mockUser = { uid: config.authContext.uid,\nroles: config.authContext.roles } as User;\n const authenticatedDriver = await this.driver.withAuth(mockUser);\n row = await authenticatedDriver.fetchOne({\n path: config.path,\n id: config.id,\n collection: registryCollection\n });\n } else {\n row = await this.dataService.fetchOne(config.path, config.id);\n }\n\n if (callback) {\n callback(row || null);\n }\n } catch (error) {\n logger.error(`Error fetching row for subscription ${subscriptionId}`, { error: error });\n }\n }\n\n /**\n * Unsubscribe from a subscription\n */\n unsubscribe(subscriptionId: string): void {\n const subscription = this.subscriptions.get(subscriptionId);\n if (subscription) {\n if (subscription.changeStream) {\n subscription.changeStream.close().catch((err) => logger.error(\"Operation failed\", { error: err }));\n }\n this.subscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Notify all relevant subscribers of an row update\n * This is called after save/delete operations to push updates\n */\n async notifyUpdate(\n path: string,\n id: string,\n row: Record<string, unknown> | null,\n _databaseId?: string\n ): Promise<void> {\n // Find all subscriptions that might be affected by this update\n for (const [subscriptionId, subscription] of this.subscriptions) {\n if (subscription.type === \"single\") {\n const config = subscription.config as SingleSubscriptionConfig;\n if (config.path === path && config.id.toString() === id) {\n if (subscription.callback) {\n subscription.callback(row);\n }\n }\n } else if (subscription.type === \"collection\") {\n const config = subscription.config as CollectionSubscriptionConfig;\n if (config.path === path) {\n // Re-fetch the collection to get updated data\n await this.fetchAndNotifyCollection(subscriptionId, config, subscription.callback);\n }\n }\n }\n }\n\n /**\n * Get all active subscriptions (for debugging)\n */\n getSubscriptions(): Map<string, Subscription> {\n return this.subscriptions;\n }\n\n /**\n * Close all subscriptions\n */\n async closeAll(): Promise<void> {\n for (const [subscriptionId] of this.subscriptions) {\n this.unsubscribe(subscriptionId);\n }\n }\n\n // =============================================================================\n // WebSocket Client Management (parity with PostgreSQL RealtimeService)\n // =============================================================================\n\n /**\n * Register a WebSocket client for real-time communication\n */\n addClient(clientId: string, ws: WebSocket) {\n this.clients.set(clientId, ws);\n\n ws.on(\"close\", () => {\n this.removeClient(clientId);\n });\n\n ws.on(\"error\", (error) => {\n logger.error(\"WebSocket error for client\", { detail: clientId, error });\n this.removeClient(clientId);\n });\n }\n\n /**\n * Remove a WebSocket client and clean up its subscriptions\n */\n private removeClient(clientId: string) {\n this.clients.delete(clientId);\n }\n\n /**\n * Handle an incoming WebSocket message for subscription management\n */\n async handleClientMessage(\n clientId: string,\n message: { type: string; payload?: any; subscriptionId?: string },\n _authContext?: { uid: string; roles: unknown[] }\n ): Promise<void> {\n const ws = this.clients.get(clientId);\n if (!ws) return;\n\n const authContext = _authContext ? { uid: _authContext.uid,\nroles: (_authContext.roles ?? []).map(String) } : undefined;\n\n switch (message.type) {\n case \"subscribe_collection\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (!subscriptionId) return;\n\n this.subscribeToCollection(\n subscriptionId,\n {\n clientId,\n path: message.payload?.path,\n filter: message.payload?.filter,\n orderBy: message.payload?.orderBy,\n order: message.payload?.order,\n limit: message.payload?.limit,\n startAfter: message.payload?.startAfter,\n searchString: message.payload?.searchString,\n authContext\n },\n (rows) => {\n ws.send(JSON.stringify({\n type: \"collection_update\",\n subscriptionId,\n rows\n }));\n }\n );\n break;\n }\n case \"subscribe_one\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (!subscriptionId) return;\n\n this.subscribeToOne(\n subscriptionId,\n {\n clientId,\n path: message.payload?.path,\n id: message.payload?.id,\n authContext\n },\n (row) => {\n ws.send(JSON.stringify({\n type: \"single_update\",\n subscriptionId,\n row\n }));\n }\n );\n break;\n }\n case \"unsubscribe\": {\n const subscriptionId = message.payload?.subscriptionId ?? message.subscriptionId;\n if (subscriptionId) {\n this.unsubscribe(subscriptionId);\n }\n break;\n }\n }\n }\n}\n","import { Db, ObjectId } from \"mongodb\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * Deep equality without JSON.stringify.\n * Handles primitives, arrays, Dates, and plain objects recursively.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === \"object\" && typeof b === \"object\") {\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every(k => deepEqual(aObj[k], bObj[k]));\n }\n return false;\n}\n\n/**\n * Shallow comparison to find top-level keys that changed between two objects.\n */\nexport function findChangedFields(\n oldValues: Record<string, unknown>,\n newValues: Record<string, unknown>\n): string[] | null {\n const changed: string[] = [];\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldVal = oldValues[key];\n const newVal = newValues[key];\n\n // Skip internal metadata\n if (key.startsWith(\"__\")) continue;\n\n if (oldVal !== newVal) {\n // For objects/arrays, use structural comparison\n if (\n typeof oldVal === \"object\" && oldVal !== null &&\n typeof newVal === \"object\" && newVal !== null\n ) {\n if (!deepEqual(oldVal, newVal)) {\n changed.push(key);\n }\n } else {\n changed.push(key);\n }\n }\n }\n\n return changed.length > 0 ? changed : null;\n}\n\nexport type { RecordHistoryParams, HistoryRetentionConfig } from \"@rebasepro/types\";\nimport type { EntityHistoryEntry, RecordHistoryParams, HistoryRetentionConfig } from \"@rebasepro/types\";\n\n/**\n * A history entry as MongoDB stores it — not as it travels.\n *\n * Two fields differ from {@link EntityHistoryEntry}: the driver's own `_id`,\n * and `updated_at` as a native `Date` so the retention query can compare it\n * with `$lt`. Both of these used to be on an interface *named* `HistoryEntry`,\n * which is also what `@rebasepro/server-postgres` called its wire shape — so\n * the same name meant `string` in one driver and `Date` in the other.\n */\nexport interface MongoHistoryDocument extends Omit<EntityHistoryEntry, \"updated_at\"> {\n _id?: ObjectId;\n updated_at: Date;\n}\n\nconst DEFAULT_RETENTION: HistoryRetentionConfig = {\n maxEntries: 200,\n ttlDays: 90\n};\n\nexport class MongoHistoryService {\n public retention: HistoryRetentionConfig;\n\n constructor(\n private db: Db,\n retention?: Partial<HistoryRetentionConfig>\n ) {\n this.retention = { ...DEFAULT_RETENTION,\n...retention };\n }\n\n async recordHistory(params: RecordHistoryParams): Promise<void> {\n const {\n tableName,\n id,\n action,\n values,\n previousValues,\n updatedBy\n } = params;\n\n const changedFields = previousValues && values\n ? findChangedFields(previousValues, values)\n : null;\n\n if (action === \"update\" && (!changedFields || changedFields.length === 0)) {\n return;\n }\n\n try {\n const entry: MongoHistoryDocument = {\n id: new ObjectId().toString(),\n table_name: tableName,\n entity_id: String(id),\n action,\n changed_fields: changedFields,\n values: values || null,\n previous_values: previousValues || null,\n updated_by: updatedBy || null,\n updated_at: new Date()\n };\n\n await this.db.collection(\"__rebase_history\").insertOne(entry);\n\n // Non-blocking prune for this specific row\n this.pruneHistory(String(id), tableName).catch(e => {\n logger.error(`[HistoryService] Failed to prune history for ${tableName}/${id}`, { error: e });\n });\n } catch (error) {\n logger.error(`[HistoryService] Failed to record history for ${tableName}/${id}`, { error: error });\n }\n }\n\n private async pruneHistory(id: string, tableName: string): Promise<void> {\n const collection = this.db.collection(\"__rebase_history\");\n\n // 1. Enforce maxEntries\n const count = await collection.countDocuments({ entity_id: id,\ntable_name: tableName });\n if (count > this.retention.maxEntries) {\n const toDelete = count - this.retention.maxEntries;\n const oldestEntries = await collection\n .find({ entity_id: id,\ntable_name: tableName })\n .sort({ updated_at: 1 })\n .limit(toDelete)\n .toArray();\n\n if (oldestEntries.length > 0) {\n const idsToDelete = oldestEntries.map(entry => entry._id);\n await collection.deleteMany({ _id: { $in: idsToDelete } });\n }\n }\n\n // 2. Enforce ttlDays\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - this.retention.ttlDays);\n\n await collection.deleteMany({\n entity_id: id,\n table_name: tableName,\n updated_at: { $lt: cutoffDate }\n });\n }\n}\n","/**\n * MongoDB DataDriver Delegate\n *\n * Implements the DataDriver interface for Rebase frontend integration.\n * This is the main entry point for Rebase to interact with MongoDB.\n */\n\nimport { Db } from \"mongodb\";\nimport {\n DataDriver,\n DeleteProps,\n Entity,\n CollectionConfig,\n FetchCollectionProps,\n FetchOneProps,\n ListenCollectionProps,\n ListenOneProps,\n SaveProps,\n RebaseCallContext,\n CollectionRegistryInterface,\n User,\n RebaseClient,\n RebaseData,\n RebaseSdkData,\n SecurityRule\n} from \"@rebasepro/types\";\nimport { MongoDataService } from \"../db/MongoDataService\";\nimport { MongoRealtimeService } from \"./MongoRealtimeService\";\nimport { MongoHistoryService } from \"./MongoHistoryService\";\nimport { buildPropertyCallbacks, updateDateAutoValues, buildSdkData, checkOperation } from \"@rebasepro/common\";\nimport { mergeDeep } from \"@rebasepro/utils\";\nimport { Filter, Document } from \"mongodb\";\nimport { ApiError } from \"@rebasepro/server\";\nimport { MongoConditionBuilder } from \"../db/MongoConditionBuilder\";\nimport { logger } from \"@rebasepro/server\";\n\n/**\n * MongoDB DataDriver Delegate\n *\n * Implements the DataDriver interface for Rebase.\n * Provides all data operations needed by the Rebase frontend.\n */\nexport class MongoDriver implements DataDriver {\n key = \"mongodb\";\n initialised = true;\n\n private dataService: MongoDataService;\n private realtimeService: MongoRealtimeService;\n public historyService: MongoHistoryService;\n public user?: User;\n public data: RebaseSdkData;\n public client?: RebaseClient;\n\n constructor(\n private db: Db,\n realtimeService?: MongoRealtimeService,\n historyService?: MongoHistoryService,\n public readonly registry?: CollectionRegistryInterface,\n user?: User\n ) {\n this.dataService = new MongoDataService(db);\n this.realtimeService = realtimeService ?? new MongoRealtimeService(db);\n this.historyService = historyService ?? new MongoHistoryService(db);\n this.user = user;\n this.data = buildSdkData(this);\n this.realtimeService.setDataDriver(this);\n }\n\n /**\n * Get the current timestamp\n */\n currentTime(): Date {\n return new Date();\n }\n\n /**\n * Resolve a collection's callbacks and property callbacks from the registry.\n * Used by AuthenticatedMongoDriver to apply callbacks after RLS filtering.\n */\n resolveCollectionCallbacks<M extends Record<string, unknown>>(\n collection: CollectionConfig<M> | undefined,\n path: string\n ) {\n if (!collection && !path) return { collection: undefined,\ncallbacks: undefined,\nglobalCallbacks: undefined,\npropertyCallbacks: undefined };\n const registryCollection = this.registry?.getCollectionByPath(path);\n const resolvedCollection = registryCollection\n ? ({ ...collection,\n...registryCollection } as CollectionConfig<M>)\n : (collection as CollectionConfig<M>);\n\n const callbacks = resolvedCollection?.callbacks;\n const globalCallbacks = this.registry?.getGlobalCallbacks();\n const properties = resolvedCollection?.properties;\n let propertyCallbacks;\n if (properties) {\n propertyCallbacks = buildPropertyCallbacks(properties);\n }\n return {\n collection: resolvedCollection,\n callbacks,\n globalCallbacks,\n propertyCallbacks\n };\n }\n\n /**\n * Fetch a collection of rows\n */\n async fetchCollection<M extends Record<string, any>>({\n path,\n collection,\n filter,\n limit,\n startAfter,\n orderBy,\n searchString,\n order\n }: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const rows = await this.dataService.fetchCollection<M>(path, {\n filter,\n limit,\n startAfter,\n orderBy,\n order,\n searchString,\n collection: collection as CollectionConfig\n });\n\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n if (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext; // Backend context\n return Promise.all(rows.map(async (row) => {\n let fetched = row;\n if (globalCallbacks?.afterRead) {\n fetched = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (callbacks?.afterRead) {\n fetched = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (propertyCallbacks?.afterRead) {\n fetched = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n return fetched;\n }));\n }\n\n return rows;\n }\n\n /**\n * Listen to collection changes\n */\n listenCollection<M extends Record<string, any>>({\n path,\n collection,\n filter,\n limit,\n startAfter,\n orderBy,\n searchString,\n order,\n onUpdate,\n onError\n }: ListenCollectionProps<M>): () => void {\n const subscriptionId = this.generateSubscriptionId();\n\n const callback = (rows: Record<string, unknown>[]) => {\n try {\n onUpdate(rows);\n } catch (error) {\n logger.error(\"Error in collection update callback\", { error: error });\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n };\n\n this.realtimeService.subscribeToCollection(\n subscriptionId,\n {\n clientId: \"driver\",\n path,\n filter,\n orderBy,\n order,\n limit,\n startAfter,\n searchString\n },\n callback\n );\n\n // Return unsubscribe function\n return () => {\n this.realtimeService.unsubscribe(subscriptionId);\n };\n }\n\n /**\n * Fetch a single row\n */\n async fetchOne<M extends Record<string, any>>({\n path,\n id,\n databaseId,\n collection\n }: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n let row = await this.dataService.fetchOne<M>(path, id, databaseId);\n\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n if (row && (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext; // Backend context\n let processedRow: Record<string, unknown> = row;\n if (globalCallbacks?.afterRead) {\n processedRow = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n if (callbacks?.afterRead) {\n processedRow = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n if (propertyCallbacks?.afterRead) {\n processedRow = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: processedRow,\n context: contextForCallback\n }) ?? processedRow;\n }\n row = processedRow;\n }\n\n return row;\n }\n\n /**\n * Listen to row changes\n */\n listenOne<M extends Record<string, any>>({\n path,\n id,\n collection,\n onUpdate,\n onError\n }: ListenOneProps<M>): () => void {\n const subscriptionId = this.generateSubscriptionId();\n\n const callback = (row: Record<string, unknown> | null) => {\n try {\n onUpdate(row);\n } catch (error) {\n logger.error(\"Error in row update callback\", { error: error });\n if (onError) {\n onError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n };\n\n this.realtimeService.subscribeToOne(\n subscriptionId,\n {\n clientId: \"driver\",\n path,\n id\n },\n callback\n );\n\n // Return unsubscribe function\n return () => {\n this.realtimeService.unsubscribe(subscriptionId);\n };\n }\n\n /**\n * Save an row (create or update)\n */\n async save<M extends Record<string, any>>({\n path,\n id,\n values,\n collection,\n status\n }: SaveProps<M>): Promise<Record<string, unknown>> {\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, path);\n\n let updatedValues = values;\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext;\n\n // Fetch previous values for callbacks AND history recording\n let previousValuesForHistory: Partial<M> | undefined;\n if (status === \"existing\" && id) {\n const existing = await this.dataService.fetchOne<M>(path, id, resolvedCollection?.databaseId);\n if (existing) {\n const { id: _existingId, ...existingValues } = existing;\n previousValuesForHistory = existingValues as Partial<M>;\n }\n }\n\n if (globalCallbacks?.beforeSave || callbacks?.beforeSave || propertyCallbacks?.beforeSave) {\n if (globalCallbacks?.beforeSave) {\n const result = await globalCallbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n\n if (callbacks?.beforeSave) {\n const result = await callbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n\n if (propertyCallbacks?.beforeSave) {\n const result = await propertyCallbacks.beforeSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n }\n\n // Apply autoValue timestamps (on_create / on_update) at the application layer.\n if (resolvedCollection?.properties) {\n updatedValues = updateDateAutoValues({\n inputValues: updatedValues,\n properties: resolvedCollection.properties,\n status: status ?? \"new\",\n timestampNowValue: new Date()\n });\n }\n\n try {\n let savedRow = await this.dataService.save<M>(\n path,\n updatedValues,\n id,\n resolvedCollection?.databaseId\n );\n\n if (savedRow && (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n if (globalCallbacks?.afterRead) {\n savedRow = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n if (callbacks?.afterRead) {\n savedRow = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n if (propertyCallbacks?.afterRead) {\n savedRow = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n row: savedRow,\n context: contextForCallback\n }) ?? savedRow;\n }\n }\n\n const savedId = savedRow.id as string | number;\n const { id: _savedId, ...savedValues } = savedRow;\n\n if (globalCallbacks?.afterSave || callbacks?.afterSave || propertyCallbacks?.afterSave) {\n if (globalCallbacks?.afterSave) {\n await globalCallbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n if (callbacks?.afterSave) {\n await callbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues as Partial<M>,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterSave) {\n await propertyCallbacks.afterSave({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: savedId,\n values: savedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n }\n\n // Record row history (fire-and-forget, never blocks the save)\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n tableName: path,\n id: savedId.toString(),\n action: status === \"new\" ? \"create\" : \"update\",\n values: savedValues as Record<string, unknown>,\n previousValues: previousValuesForHistory as Record<string, unknown> | undefined,\n updatedBy: this.user?.uid\n }).catch(err => {\n logger.error(`Failed to record history for ${path}/${savedId}`, { error: err });\n });\n }\n\n // Notify real-time subscribers\n await this.realtimeService.notifyUpdate(\n path,\n savedId.toString(),\n savedRow\n );\n\n return savedRow;\n } catch (error) {\n if (callbacks?.afterSaveError || propertyCallbacks?.afterSaveError) {\n if (callbacks?.afterSaveError) {\n await callbacks.afterSaveError({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: id || \"unknown\",\n values: updatedValues,\n previousValues: undefined,\n status,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterSaveError) {\n await propertyCallbacks.afterSaveError({\n collection: resolvedCollection as CollectionConfig<M>,\n path,\n id: id || \"unknown\",\n values: updatedValues,\n previousValues: undefined,\n status,\n context: contextForCallback\n });\n }\n }\n throw error;\n }\n }\n\n /**\n * Delete an row\n */\n async delete<M extends Record<string, any>>({\n row,\n collection\n }: DeleteProps<M>): Promise<void> {\n const { collection: resolvedCollection, callbacks, globalCallbacks, propertyCallbacks } = this.resolveCollectionCallbacks(collection, row.path);\n\n const callbackRow: Record<string, unknown> = { id: row.id, ...(row.values ?? {}) };\n\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.client,\n storageSource: this.client?.storage\n } as unknown as RebaseCallContext;\n\n if (globalCallbacks?.beforeDelete || callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {\n let preventDefault = false;\n if (globalCallbacks?.beforeDelete) {\n const result = await globalCallbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (callbacks?.beforeDelete) {\n const result = await callbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (propertyCallbacks?.beforeDelete) {\n const result = await propertyCallbacks.beforeDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (preventDefault) {\n return;\n }\n }\n\n await this.dataService.delete(row.path, row.id);\n\n if (globalCallbacks?.afterDelete || callbacks?.afterDelete || propertyCallbacks?.afterDelete) {\n if (globalCallbacks?.afterDelete) {\n await globalCallbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n if (callbacks?.afterDelete) {\n await callbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterDelete) {\n await propertyCallbacks.afterDelete({\n collection: resolvedCollection as CollectionConfig<M>,\n path: row.path,\n id: row.id,\n row: callbackRow,\n context: contextForCallback\n });\n }\n }\n\n // Record history\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n action: \"delete\",\n id: String(row.id),\n tableName: row.path,\n previousValues: row.values,\n updatedBy: this.user?.uid\n }).catch(err => {\n logger.error(`Failed to record history for ${row.path}/${row.id}`, { error: err });\n });\n }\n\n // Notify subscribers of the deletion\n await this.realtimeService.notifyUpdate(row.path, String(row.id), null);\n }\n\n /**\n * Check if a field value is unique\n */\n async checkUniqueField(\n path: string,\n name: string,\n value: any,\n id?: string,\n collection?: CollectionConfig\n ): Promise<boolean> {\n return this.dataService.checkUniqueField(path, name, value, id);\n }\n\n /**\n * Generate a new row ID\n */\n generateId(path: string, collection?: CollectionConfig): string {\n return this.dataService.generateId();\n }\n\n /**\n * Count rows in a collection\n */\n async count<M extends Record<string, any>>({\n path,\n collection,\n filter\n }: FetchCollectionProps<M>): Promise<number> {\n return this.dataService.count<M>(path, { filter });\n }\n\n /**\n * Generate a unique subscription ID\n */\n private generateSubscriptionId(): string {\n return `mongo_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Check if the delegate is ready\n */\n isReady(): boolean {\n return this.initialised;\n }\n\n /**\n * Get the underlying row service for direct access\n */\n getDataService(): MongoDataService {\n return this.dataService;\n }\n\n /**\n * Get the underlying realtime service for direct access\n */\n getRealtimeService(): MongoRealtimeService {\n return this.realtimeService;\n }\n\n /**\n * Scope the MongoDriver with an authenticated user context\n */\n async withAuth(user: User): Promise<DataDriver> {\n return new AuthenticatedMongoDriver(this, user);\n }\n}\n\nexport class AuthenticatedMongoDriver implements DataDriver {\n key = \"mongodb\";\n initialised = true;\n public user: User;\n public data: RebaseSdkData;\n\n constructor(public delegate: MongoDriver, user: User) {\n this.user = user;\n this.data = buildSdkData(this);\n }\n\n currentTime(): Date {\n return this.delegate.currentTime();\n }\n\n async fetchCollection<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const rlsFilter = buildMongoFilterFromSecurityRules(resolvedCollection, this.user, \"select\");\n if (rlsFilter === null) {\n return [];\n }\n\n const userQuery = MongoConditionBuilder.buildQuery({\n filter: props.filter,\n searchString: props.searchString,\n properties: resolvedCollection?.properties\n });\n\n const combinedQuery = Object.keys(rlsFilter).length > 0\n ? ({ $and: [userQuery, rlsFilter] } as Filter<Document>)\n : userQuery;\n\n const originalService = this.delegate.getDataService();\n const rows = await originalService.fetchCollection<M>(props.path, {\n ...props,\n rawQuery: combinedQuery,\n collection: resolvedCollection\n });\n\n const { callbacks, globalCallbacks, propertyCallbacks } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n\n if (globalCallbacks?.afterRead || callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: this.user,\n driver: this,\n data: this.data,\n client: this.delegate.client,\n storageSource: this.delegate.client?.storage\n } as unknown as RebaseCallContext;\n return Promise.all(rows.map(async (row) => {\n let fetched = row;\n if (globalCallbacks?.afterRead) {\n fetched = await globalCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (callbacks?.afterRead) {\n fetched = await callbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (propertyCallbacks?.afterRead) {\n fetched = await propertyCallbacks.afterRead({\n collection: resolvedCollection as CollectionConfig<M>,\n path: props.path,\n row: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n return fetched;\n }));\n }\n\n return rows;\n }\n\n listenCollection<M extends Record<string, any>>(props: ListenCollectionProps<M>): () => void {\n const unsubscribe = this.delegate.listenCollection(props);\n const authContext = { uid: this.user.uid,\nroles: this.user.roles ?? [] };\n const subscriptions = this.delegate.getRealtimeService().getSubscriptions();\n const lastEntry = Array.from(subscriptions.entries()).pop();\n const lastSub = lastEntry?.[1];\n if (lastSub && lastSub.config.clientId === \"driver\") {\n lastSub.authContext = authContext;\n }\n return unsubscribe;\n }\n\n async fetchOne<M extends Record<string, any>>(props: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const row = await this.delegate.fetchOne(props);\n if (row) {\n const authorized = checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(row, props.path), \"select\", { onUnknown: \"deny\" });\n if (!authorized) {\n return undefined;\n }\n }\n return row;\n }\n\n listenOne<M extends Record<string, any>>(props: ListenOneProps<M>): () => void {\n const unsubscribe = this.delegate.listenOne(props);\n const authContext = { uid: this.user.uid,\nroles: this.user.roles ?? [] };\n const subscriptions = this.delegate.getRealtimeService().getSubscriptions();\n const lastEntry = Array.from(subscriptions.entries()).pop();\n const lastSub = lastEntry?.[1];\n if (lastSub && lastSub.config.clientId === \"driver\") {\n lastSub.authContext = authContext;\n }\n return unsubscribe;\n }\n\n async save<M extends Record<string, any>>(props: SaveProps<M>): Promise<Record<string, unknown>> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n\n if (props.status === \"existing\" && props.id) {\n const existing = await this.delegate.fetchOne({ path: props.path,\nid: props.id,\ncollection: resolvedCollection });\n if (!existing || !checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(existing, props.path), \"update\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n } else {\n const tempEntity = { id: props.id || \"new\",\npath: props.path,\nvalues: props.values } as Entity;\n if (!checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, tempEntity, \"insert\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n }\n\n const saved = await this.delegate.save({\n ...props,\n collection: resolvedCollection\n });\n\n // After save / withCheck rules verification\n if (!checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(saved, props.path), props.status === \"existing\" ? \"update\" : \"insert\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n\n return saved;\n }\n\n async delete<M extends Record<string, any>>(props: DeleteProps<M>): Promise<void> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.row.path);\n\n const existing = await this.delegate.fetchOne({ path: props.row.path,\nid: props.row.id,\ncollection: resolvedCollection });\n if (!existing || !checkOperation(resolvedCollection as CollectionConfig, { user: this.user }, rowToEntityForCheck(existing, props.row.path), \"delete\", { onUnknown: \"deny\" })) {\n throw ApiError.forbidden(\"Forbidden\");\n }\n\n return this.delegate.delete(props);\n }\n\n async checkUniqueField(\n path: string,\n name: string,\n value: any,\n id?: string,\n collection?: CollectionConfig\n ): Promise<boolean> {\n return this.delegate.checkUniqueField(path, name, value, id, collection);\n }\n\n generateId(path: string, collection?: CollectionConfig): string {\n return this.delegate.generateId(path, collection);\n }\n\n async count<M extends Record<string, any>>(props: FetchCollectionProps<M>): Promise<number> {\n const { collection: resolvedCollection } = this.delegate.resolveCollectionCallbacks(props.collection, props.path);\n const rlsFilter = buildMongoFilterFromSecurityRules(resolvedCollection, this.user, \"select\");\n if (rlsFilter === null) {\n return 0;\n }\n\n const userQuery = MongoConditionBuilder.buildQuery({\n filter: props.filter,\n searchString: props.searchString,\n properties: resolvedCollection?.properties\n });\n\n const combinedQuery = Object.keys(rlsFilter).length > 0\n ? ({ $and: [userQuery, rlsFilter] } as Filter<Document>)\n : userQuery;\n\n const originalService = this.delegate.getDataService();\n return originalService.count(props.path, {\n ...props,\n rawQuery: combinedQuery\n });\n }\n\n isReady(): boolean {\n return this.delegate.isReady();\n }\n}\n\n/**\n * Wrap a flat row into the Entity shape expected by `checkOperation`,\n * which evaluates security rules against `row.values`.\n */\nfunction rowToEntityForCheck(row: Record<string, unknown>, path: string): Entity {\n return {\n id: row.id as string | number,\n path,\n values: row\n };\n}\n\nfunction getMongoFilterForSQL(sqlString: string, user: User): Filter<Document> | null {\n let cleanedSQL = sqlString.trim();\n while (cleanedSQL.startsWith(\"(\") && cleanedSQL.endsWith(\")\")) {\n let openCount = 0;\n let isEnclosing = true;\n for (let i = 0; i < cleanedSQL.length - 1; i++) {\n if (cleanedSQL[i] === \"(\") openCount++;\n else if (cleanedSQL[i] === \")\") openCount--;\n if (openCount === 0) {\n isEnclosing = false;\n break;\n }\n }\n if (isEnclosing) {\n cleanedSQL = cleanedSQL.substring(1, cleanedSQL.length - 1).trim();\n } else {\n break;\n }\n }\n\n const splitByTopLevel = (str: string, delimiter: string) => {\n const parts: string[] = [];\n let current = \"\";\n let openCount = 0;\n let i = 0;\n while (i < str.length) {\n if (str[i] === \"(\") openCount++;\n else if (str[i] === \")\") openCount--;\n\n if (openCount === 0 && str.substring(i).toUpperCase().startsWith(delimiter)) {\n parts.push(current);\n current = \"\";\n i += delimiter.length;\n } else {\n current += str[i];\n i++;\n }\n }\n parts.push(current);\n return parts;\n };\n\n const orParts = splitByTopLevel(cleanedSQL, \" OR \");\n if (orParts.length > 1) {\n const subFilters = orParts.map(part => getMongoFilterForSQL(part, user)).filter(f => f !== null) as Filter<Document>[];\n if (subFilters.length === 0) return null;\n if (subFilters.length === 1) return subFilters[0];\n return { $or: subFilters } as Filter<Document>;\n }\n\n const andParts = splitByTopLevel(cleanedSQL, \" AND \");\n if (andParts.length > 1) {\n const subFilters = andParts.map(part => getMongoFilterForSQL(part, user)).filter(f => f !== null) as Filter<Document>[];\n if (subFilters.length === 0) return null;\n if (subFilters.length === 1) return subFilters[0];\n return { $and: subFilters } as Filter<Document>;\n }\n\n const roleIntersectMatch = cleanedSQL.match(/string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*&&\\s*ARRAY\\[(.*?)\\]/i);\n if (roleIntersectMatch && roleIntersectMatch[1]) {\n const requiredRoles = roleIntersectMatch[1].split(\",\").map(r => r.trim().replace(/'/g, \"\"));\n const userRoles = user.roles || [];\n const matches = requiredRoles.some(r => userRoles.includes(r));\n return matches ? {} : { _id: { $exists: false } };\n }\n\n const roleContainMatch = cleanedSQL.match(/string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*@>\\s*ARRAY\\[(.*?)\\]/i);\n if (roleContainMatch && roleContainMatch[1]) {\n const requiredRoles = roleContainMatch[1].split(\",\").map(r => r.trim().replace(/'/g, \"\"));\n const userRoles = user.roles || [];\n const matches = requiredRoles.every(r => userRoles.includes(r));\n return matches ? {} : { _id: { $exists: false } };\n }\n\n const pattern1 = new RegExp(\"^\\\\{?([a-zA-Z0-9_]+)\\\\}?\\\\s*=\\\\s*(?:current_setting\\\\s*\\\\(\\\\s*'app\\\\.user_id'\\\\s*\\\\)|auth\\\\.uid\\\\(\\\\))\");\n const pattern2 = new RegExp(\"^(?:current_setting\\\\s*\\\\(\\\\s*'app\\\\.user_id'\\\\s*\\\\)|auth\\\\.uid\\\\(\\\\))\\\\s*=\\\\s*\\\\{?([a-zA-Z0-9_]+)\\\\}?\");\n\n const match1 = cleanedSQL.match(pattern1);\n if (match1 && match1[1]) {\n return { [match1[1]]: user.uid };\n }\n\n const match2 = cleanedSQL.match(pattern2);\n if (match2 && match2[1]) {\n return { [match2[1]]: user.uid };\n }\n\n const simpleEqualityMatch = cleanedSQL.match(/^\\{?([\\w_]+)\\}?\\s*(=|!=)\\s*'([^']+)'$/i);\n if (simpleEqualityMatch) {\n const field = simpleEqualityMatch[1];\n const operator = simpleEqualityMatch[2];\n const value = simpleEqualityMatch[3];\n if (operator === \"=\") return { [field]: value };\n if (operator === \"!=\") return { [field]: { $ne: value } };\n }\n\n return {};\n}\n\nfunction getMongoFilterForRule(rule: SecurityRule, user: User): Filter<Document> | null {\n if (rule.access === \"public\") return {};\n\n const filters: Filter<Document>[] = [];\n\n if (rule.ownerField) {\n filters.push({ [rule.ownerField]: user.uid });\n }\n\n if (rule.using) {\n const f = getMongoFilterForSQL(rule.using, user);\n if (f) filters.push(f);\n }\n\n if (rule.withCheck) {\n const f = getMongoFilterForSQL(rule.withCheck, user);\n if (f) filters.push(f);\n }\n\n if (filters.length === 0) return {};\n if (filters.length === 1) return filters[0];\n return { $and: filters } as Filter<Document>;\n}\n\nfunction buildMongoFilterFromSecurityRules<M extends Record<string, any>>(\n collection: CollectionConfig<M> | undefined,\n user: User,\n targetOperation: \"select\" | \"insert\" | \"update\" | \"delete\"\n): Filter<Document> | null {\n if (!collection || !collection.securityRules || collection.securityRules.length === 0) {\n return {};\n }\n\n const applicableRules = collection.securityRules.filter((r: SecurityRule) =>\n r.operation === targetOperation ||\n r.operation === \"all\" ||\n r.operations?.includes(targetOperation) ||\n r.operations?.includes(\"all\")\n );\n\n if (applicableRules.length === 0) {\n return null;\n }\n\n const userRoleIds = user.roles ?? [];\n const userRoles = [...userRoleIds, \"public\"];\n const roleApplicableRules = applicableRules.filter((rule: SecurityRule) => {\n if (!rule.roles || rule.roles.length === 0) return true;\n return rule.roles.some((r: string) => userRoles.includes(r));\n });\n\n if (roleApplicableRules.length === 0) {\n return null;\n }\n\n const permissiveFilters: Filter<Document>[] = [];\n const restrictiveFilters: Filter<Document>[] = [];\n\n for (const rule of roleApplicableRules) {\n const mode = rule.mode || \"permissive\";\n const filter = getMongoFilterForRule(rule, user);\n if (filter === null) {\n if (mode === \"restrictive\") {\n return null;\n }\n continue;\n }\n\n if (mode === \"restrictive\") {\n restrictiveFilters.push(filter);\n } else {\n permissiveFilters.push(filter);\n }\n }\n\n const finalAnds: Filter<Document>[] = [];\n\n if (permissiveFilters.length > 0) {\n const hasAlwaysTruePermissive = permissiveFilters.some(f => Object.keys(f).length === 0);\n if (!hasAlwaysTruePermissive) {\n if (permissiveFilters.length === 1) {\n finalAnds.push(permissiveFilters[0]);\n } else {\n finalAnds.push({ $or: permissiveFilters } as Filter<Document>);\n }\n }\n } else {\n return null;\n }\n\n if (restrictiveFilters.length > 0) {\n for (const rf of restrictiveFilters) {\n if (Object.keys(rf).length > 0) {\n finalAnds.push(rf);\n }\n }\n }\n\n if (finalAnds.length === 0) return {};\n if (finalAnds.length === 1) return finalAnds[0];\n return { $and: finalAnds } as Filter<Document>;\n}\n","/**\n * MongoDB Backend Factory\n *\n * This module provides factory functions for creating MongoDB backend instances.\n * It abstracts the creation of drivers, realtime services, and row services.\n */\n\nimport { Db, MongoClient } from \"mongodb\";\nimport { DataDriver, CollectionConfig } from \"@rebasepro/types\";\n\nimport { MongoDataService } from \"./db/MongoDataService\";\nimport { MongoRealtimeService } from \"./services/MongoRealtimeService\";\nimport { MongoDriver } from \"./services/MongoDriver\";\nimport { MongoHistoryService, HistoryRetentionConfig } from \"./services/MongoHistoryService\";\nimport { MongoDBConnection } from \"./connection\";\nimport { BackendConfig, BackendInstance, CollectionRegistryInterface, DataRepository, RealtimeProvider, DatabaseConnection, DatabaseAdmin, DocumentAdmin, SchemaAdmin, HealthCheckResult } from \"@rebasepro/types\";\n\n/**\n * Configuration for creating a MongoDB backend.\n */\nexport interface MongoBackendConfig extends BackendConfig {\n type: \"mongodb\";\n /** MongoDB database instance */\n connection: Db;\n /** MongoDB client (for connection management) */\n client: MongoClient;\n /** Collections to register (optional, can be registered later) */\n collections?: CollectionConfig[];\n /** History retention configuration */\n historyRetention?: Partial<HistoryRetentionConfig>;\n}\n\n/**\n * MongoDB-specific backend instance with additional MongoDB types.\n */\nexport interface MongoBackendInstance extends BackendInstance {\n /** The MongoDB database instance */\n db: Db;\n /** The MongoDB client */\n client: MongoClient;\n /** MongoDB DataDriver for use with Rebase */\n driver: DataDriver;\n /** Entity service for direct database operations */\n dataService: MongoDataService;\n /** Realtime service for subscriptions */\n realtimeService: MongoRealtimeService;\n /** Admin capabilities (DocumentAdmin + SchemaAdmin) */\n admin: DatabaseAdmin;\n}\n\n// =============================================================================\n// Simple Collection Registry\n// =============================================================================\n\n/**\n * Simple in-memory collection registry for MongoDB.\n */\nexport class MongoCollectionRegistry implements CollectionRegistryInterface {\n private collections = new Map<string, CollectionConfig>();\n private _globalCallbacks?: any;\n\n /**\n * Register a collection\n */\n register(collection: CollectionConfig): void {\n this.collections.set(collection.name, collection);\n }\n\n /**\n * Get a collection by its path\n */\n getCollectionByPath(path: string): CollectionConfig | undefined {\n return this.collections.get(path);\n }\n\n /**\n * Get all registered collections\n */\n getCollections(): CollectionConfig[] {\n return Array.from(this.collections.values());\n }\n\n /**\n * Get the currently registered global callbacks, if any.\n */\n getGlobalCallbacks(): any | undefined {\n return this._globalCallbacks;\n }\n\n /**\n * Set global lifecycle callbacks that apply to every collection.\n */\n setGlobalCallbacks(callbacks: any): void {\n this._globalCallbacks = callbacks;\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Create a complete MongoDB backend instance.\n *\n * This factory function creates all the necessary services for a MongoDB backend:\n * - MongoDBConnection (database connection wrapper)\n * - MongoDataService (implements DataRepository)\n * - MongoRealtimeService (implements RealtimeProvider)\n * - MongoCollectionRegistry (implements CollectionRegistryInterface)\n * - MongoDriver (for Rebase integration)\n *\n * @example\n * ```typescript\n * import { createMongoBackend } from \"@rebasepro/server-mongo\";\n *\n * const client = new MongoClient(\"mongodb://localhost:27017\");\n * await client.connect();\n * const db = client.db(\"my_database\");\n *\n * const backend = createMongoBackend({\n * type: \"mongodb\",\n * connection: db,\n * client: client,\n * collections: myCollections\n * });\n *\n * // Use the backend\n * const rows = await backend.entityRepository.fetchCollection(\"users\", {});\n * ```\n */\nexport function createMongoBackend(config: MongoBackendConfig): MongoBackendInstance {\n const { connection: db, client, collections } = config;\n\n // Create collection registry\n const collectionRegistry = new MongoCollectionRegistry();\n\n // Register collections if provided\n if (collections) {\n collections.forEach(collection => collectionRegistry.register(collection));\n }\n\n // Create services\n const dataService = new MongoDataService(db);\n const realtimeService = new MongoRealtimeService(db);\n const historyService = new MongoHistoryService(db, config.historyRetention);\n const driver = new MongoDriver(db, realtimeService, historyService, collectionRegistry);\n const mongoConnection = new MongoDBConnection(db, client);\n\n // Build admin capabilities for MongoDB\n const admin: DatabaseAdmin = {\n async executeAggregate(pipeline: Record<string, unknown>[]) {\n // Run aggregation on a collection — requires a target collection\n // from the pipeline's $match or $lookup stage:\n const firstStage = pipeline[0];\n const collName = typeof firstStage.$from === \"string\" ? firstStage.$from : \"__admin__\";\n const cursor = db.collection(collName).aggregate(pipeline);\n return await cursor.toArray() as Record<string, unknown>[];\n },\n async fetchCollectionStats(collectionName: string) {\n const stats = await db.command({ collStats: collectionName }) as { count: number; size: number };\n return { count: stats.count,\nsizeBytes: stats.size };\n },\n async fetchUnmappedTables(mappedPaths?: string[]) {\n const allCollections = await db.listCollections().toArray();\n const names = allCollections.map(c => c.name).filter(n => !n.startsWith(\"system.\"));\n if (!mappedPaths || mappedPaths.length === 0) return names;\n const mappedSet = new Set(mappedPaths.map(p => p.toLowerCase()));\n return names.filter(n => !mappedSet.has(n.toLowerCase()));\n },\n async fetchTableMetadata(collectionName: string) {\n // Sample a document to infer fields\n const sample = await db.collection(collectionName).findOne();\n if (!sample) return { columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n const columns = Object.entries(sample).map(([key, value]) => ({\n column_name: key,\n data_type: typeof value,\n udt_name: typeof value,\n is_nullable: \"YES\",\n column_default: null,\n character_maximum_length: null\n }));\n return { columns,\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n }\n } satisfies DocumentAdmin & SchemaAdmin;\n\n return {\n // Abstract interface implementations\n connection: mongoConnection,\n entityRepository: dataService,\n realtimeProvider: realtimeService,\n collectionRegistry: collectionRegistry,\n admin,\n\n // Lifecycle\n async initialize() {\n // Connection is already established via the MongoClient constructor\n },\n async healthCheck(): Promise<HealthCheckResult> {\n const start = Date.now();\n try {\n await db.command({ ping: 1 });\n return { healthy: true,\nlatencyMs: Date.now() - start };\n } catch {\n return { healthy: false,\nlatencyMs: Date.now() - start };\n }\n },\n async destroy() {\n await client.close();\n },\n\n // MongoDB-specific accessors\n db,\n client,\n driver,\n dataService,\n realtimeService\n };\n}\n\n/**\n * Create a MongoDB DataDriver.\n *\n * This is a convenience function when you only need the DataDriver\n * without the full backend instance.\n *\n * @example\n * ```typescript\n * import { createMongoDelegate } from \"@rebasepro/server-mongo\";\n *\n * const delegate = createMongoDelegate(db);\n * ```\n */\nexport function createMongoDelegate(\n db: Db,\n realtimeService?: MongoRealtimeService,\n historyService?: MongoHistoryService,\n registry?: CollectionRegistryInterface\n): MongoDriver {\n const realtime = realtimeService ?? new MongoRealtimeService(db);\n const history = historyService ?? new MongoHistoryService(db);\n return new MongoDriver(db, realtime, history, registry);\n}\n\n/**\n * Create a RealtimeService for MongoDB.\n *\n * @example\n * ```typescript\n * import { createMongoRealtimeService } from \"@rebasepro/server-mongo\";\n *\n * const realtimeService = createMongoRealtimeService(db);\n * ```\n */\nexport function createMongoRealtimeService(db: Db): MongoRealtimeService {\n return new MongoRealtimeService(db);\n}\n\n/**\n * Create a MongoDB row repository.\n *\n * @example\n * ```typescript\n * import { createMongoEntityRepository } from \"@rebasepro/server-mongo\";\n *\n * const repository = createMongoEntityRepository(db);\n * const users = await repository.fetchCollection(\"users\", {});\n * ```\n */\nexport function createMongoEntityRepository(db: Db): DataRepository {\n return new MongoDataService(db);\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a backend config is for MongoDB.\n */\nexport function isMongoBackendConfig(config: BackendConfig): config is MongoBackendConfig {\n return config.type === \"mongodb\" &&\n typeof (config as MongoBackendConfig).connection !== \"undefined\" &&\n typeof (config as MongoBackendConfig).client !== \"undefined\";\n}\n\n/**\n * Check if a driver config is for MongoDB.\n */\nexport function isMongoDriverConfig(obj: unknown): obj is { type: \"mongodb\"; connection: Db; client: MongoClient } {\n return typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as Record<string, unknown>).type === \"mongodb\" &&\n \"connection\" in obj &&\n \"client\" in obj;\n}\n","import { Db, ObjectId } from \"mongodb\";\n\n/** Loose document type that allows string _id values (Rebase convention). */\nexport interface MongoDoc { _id?: string; [key: string]: any; }\nimport {\n UserRepository,\n RoleRepository,\n TokenRepository,\n AuthRepository,\n UserData,\n CreateUserData,\n RoleData,\n CreateRoleData,\n RefreshTokenInfo,\n RefreshTokenSession,\n PasswordResetTokenInfo,\n MagicLinkTokenInfo,\n UserIdentityData,\n ListUsersOptions,\n PaginatedUsersResult,\n MfaFactor,\n MfaChallengeInfo\n} from \"@rebasepro/server\";\n\nexport type Role = RoleData;\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction toUser(doc: any): UserData {\n return {\n id: doc._id || doc.id,\n email: doc.email,\n passwordHash: doc.passwordHash ?? null,\n displayName: doc.displayName ?? null,\n photoUrl: doc.photoUrl ?? null,\n emailVerified: doc.emailVerified ?? false,\n emailVerificationToken: doc.emailVerificationToken ?? null,\n emailVerificationSentAt: doc.emailVerificationSentAt ? new Date(doc.emailVerificationSentAt) : null,\n createdAt: new Date(doc.createdAt),\n updatedAt: new Date(doc.updatedAt)\n };\n}\n\nexport class MongoUserService implements UserRepository {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_users\");\n }\n\n private get identitiesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_user_identities\");\n }\n\n private get userRolesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_user_roles\");\n }\n\n private get rolesCollection() {\n return this.db.collection<MongoDoc>(\"rebase_roles\");\n }\n\n async createUser(data: CreateUserData): Promise<UserData> {\n const id = new ObjectId().toString();\n const now = new Date();\n const doc = {\n _id: id,\n id,\n email: data.email.toLowerCase(),\n passwordHash: data.passwordHash ?? null,\n displayName: data.displayName ?? null,\n photoUrl: data.photoUrl ?? null,\n emailVerified: data.emailVerified ?? false,\n createdAt: now,\n updatedAt: now\n };\n await this.collection.insertOne(doc);\n return toUser(doc);\n }\n\n async getUserById(id: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ id });\n return doc ? toUser(doc) : null;\n }\n\n async getUserByEmail(email: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ email: email.toLowerCase() });\n return doc ? toUser(doc) : null;\n }\n\n async getUserByIdentity(provider: string, providerId: string): Promise<UserData | null> {\n const identity = await this.identitiesCollection.findOne({ provider,\nproviderId });\n if (!identity) return null;\n return this.getUserById(identity.uid);\n }\n\n async getUserIdentities(uid: string): Promise<UserIdentityData[]> {\n const docs = await this.identitiesCollection.find({ uid }).toArray();\n return docs.map(doc => ({\n id: doc.id,\n uid: doc.uid,\n provider: doc.provider,\n providerId: doc.providerId,\n profileData: doc.profileData ?? null,\n createdAt: new Date(doc.createdAt),\n updatedAt: new Date(doc.updatedAt)\n }));\n }\n\n async linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n const now = new Date();\n await this.identitiesCollection.updateOne(\n { provider,\nproviderId },\n {\n $setOnInsert: {\n _id: new ObjectId().toString(),\n id: new ObjectId().toString(),\n uid,\n provider,\n providerId,\n createdAt: now\n },\n $set: {\n profileData: profileData ?? null,\n updatedAt: now\n }\n },\n { upsert: true }\n );\n }\n\n async updateUser(id: string, data: Partial<Omit<CreateUserData, \"id\">>): Promise<UserData | null> {\n const updateData: Record<string, unknown> = { ...data,\nupdatedAt: new Date() };\n if (typeof updateData.email === \"string\") updateData.email = updateData.email.toLowerCase();\n\n await this.collection.updateOne({ id }, { $set: updateData });\n return this.getUserById(id);\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.collection.deleteOne({ id });\n await this.identitiesCollection.deleteMany({ uid: id });\n await this.userRolesCollection.deleteMany({ uid: id });\n }\n\n async listUsers(): Promise<UserData[]> {\n const docs = await this.collection.find().toArray();\n return docs.map(toUser);\n }\n\n async listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult> {\n const limit = options?.limit ?? 25;\n const offset = options?.offset ?? 0;\n const search = options?.search?.trim() || \"\";\n const orderBy = options?.orderBy || \"createdAt\";\n const orderDir = options?.orderDir || \"desc\";\n const roleId = options?.roleId;\n\n const query: Record<string, unknown> = {};\n\n if (search) {\n const escapedSearch = escapeRegExp(search);\n query.$or = [\n { email: { $regex: escapedSearch,\n$options: \"i\" } },\n { displayName: { $regex: escapedSearch,\n$options: \"i\" } }\n ];\n }\n\n if (roleId) {\n const userRoles = await this.userRolesCollection.find({ roleId }).toArray();\n const userIds = userRoles.map(ur => ur.uid);\n query.id = { $in: userIds };\n }\n\n const sort: Record<string, 1 | -1> = {};\n sort[orderBy] = orderDir === \"asc\" ? 1 : -1;\n\n const total = await this.collection.countDocuments(query);\n const docs = await this.collection.find(query).sort(sort).skip(offset).limit(limit).toArray();\n\n return {\n users: docs.map(toUser),\n total,\n limit,\n offset\n };\n }\n\n async updatePassword(id: string, passwordHash: string): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { passwordHash,\nupdatedAt: new Date() } }\n );\n }\n\n async setEmailVerified(id: string, verified: boolean): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { emailVerified: verified,\nemailVerificationToken: null,\nupdatedAt: new Date() } }\n );\n }\n\n async setVerificationToken(id: string, token: string | null): Promise<void> {\n await this.collection.updateOne(\n { id },\n { $set: { emailVerificationToken: token,\nemailVerificationSentAt: token ? new Date() : null,\nupdatedAt: new Date() } }\n );\n }\n\n async getUserByVerificationToken(token: string): Promise<UserData | null> {\n const doc = await this.collection.findOne({ emailVerificationToken: token });\n return doc ? toUser(doc) : null;\n }\n\n async getUserRoles(uid: string): Promise<RoleData[]> {\n const userRoles = await this.userRolesCollection.find({ uid }).toArray();\n const roleIds = userRoles.map(ur => ur.roleId);\n if (roleIds.length === 0) return [];\n\n const roles = await this.rolesCollection.find({ id: { $in: roleIds } }).toArray();\n return roles.map(r => ({\n id: r.id,\n name: r.name,\n isAdmin: r.isAdmin ?? false,\n defaultPermissions: r.defaultPermissions ?? null,\n collectionPermissions: r.collectionPermissions ?? null\n }));\n }\n\n async getUserRoleIds(uid: string): Promise<string[]> {\n const userRoles = await this.userRolesCollection.find({ uid }).toArray();\n return userRoles.map(ur => ur.roleId);\n }\n\n async setUserRoles(uid: string, roleIds: string[]): Promise<void> {\n await this.userRolesCollection.deleteMany({ uid });\n if (roleIds.length > 0) {\n const docs = roleIds.map(roleId => ({\n _id: new ObjectId().toString(),\n uid,\n roleId\n }));\n await this.userRolesCollection.insertMany(docs);\n }\n }\n\n async assignDefaultRole(uid: string, roleId: string): Promise<void> {\n await this.userRolesCollection.updateOne(\n { uid,\nroleId },\n { $setOnInsert: { _id: new ObjectId().toString(),\nuid,\nroleId } },\n { upsert: true }\n );\n }\n\n async getUserWithRoles(uid: string): Promise<{ user: UserData; roles: RoleData[] } | null> {\n const user = await this.getUserById(uid);\n if (!user) return null;\n const roles = await this.getUserRoles(uid);\n return { user,\nroles };\n }\n}\n\nexport class MongoRoleService implements RoleRepository {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_roles\");\n }\n\n async getRoleById(id: string): Promise<RoleData | null> {\n const doc = await this.collection.findOne({ id });\n if (!doc) return null;\n return {\n id: doc.id,\n name: doc.name,\n isAdmin: doc.isAdmin ?? false,\n defaultPermissions: doc.defaultPermissions ?? null,\n collectionPermissions: doc.collectionPermissions ?? null\n };\n }\n\n async listRoles(): Promise<RoleData[]> {\n const docs = await this.collection.find().sort({ name: 1 }).toArray();\n return docs.map(doc => ({\n id: doc.id,\n name: doc.name,\n isAdmin: doc.isAdmin ?? false,\n defaultPermissions: doc.defaultPermissions ?? null,\n collectionPermissions: doc.collectionPermissions ?? null\n }));\n }\n\n async createRole(data: CreateRoleData): Promise<RoleData> {\n const doc = {\n _id: data.id,\n id: data.id,\n name: data.name,\n isAdmin: data.isAdmin ?? false,\n defaultPermissions: data.defaultPermissions ?? null,\n collectionPermissions: data.collectionPermissions ?? null\n };\n await this.collection.insertOne(doc);\n return { ...doc } as RoleData;\n }\n\n async updateRole(id: string, data: Partial<Omit<RoleData, \"id\">>): Promise<RoleData | null> {\n await this.collection.updateOne({ id }, { $set: data });\n return this.getRoleById(id);\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.collection.deleteOne({ id });\n await this.db.collection(\"rebase_user_roles\").deleteMany({ roleId: id });\n }\n}\n\nexport class MongoRefreshTokenService {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_refresh_tokens\");\n }\n\n private toInfo(doc: MongoDoc): RefreshTokenInfo {\n return {\n id: doc.id,\n uid: doc.uid,\n tokenHash: doc.tokenHash,\n expiresAt: new Date(doc.expiresAt),\n createdAt: new Date(doc.createdAt),\n userAgent: doc.userAgent,\n ipAddress: doc.ipAddress,\n sessionId: doc.sessionId,\n rotatedAt: doc.rotatedAt ? new Date(doc.rotatedAt) : null,\n revoked: Boolean(doc.revoked),\n sessionStartedAt: new Date(doc.sessionStartedAt || doc.createdAt)\n };\n }\n\n async createToken(\n uid: string,\n tokenHash: string,\n expiresAt: Date,\n userAgent?: string,\n ipAddress?: string,\n session?: RefreshTokenSession\n ): Promise<void> {\n const safeUserAgent = userAgent || \"\";\n const safeIpAddress = ipAddress || \"\";\n\n // No deleteMany first. Tokens of one sign-in accumulate under a shared\n // sessionId and are pruned once nobody can still be holding them —\n // evicting by (uid, userAgent, ipAddress) is what used to sign out a\n // second browser profile behind the same address.\n const now = new Date();\n await this.collection.insertOne({\n _id: new ObjectId().toString(),\n id: new ObjectId().toString(),\n uid,\n tokenHash,\n expiresAt,\n createdAt: now,\n userAgent: safeUserAgent,\n ipAddress: safeIpAddress,\n sessionId: session?.id ?? new ObjectId().toString(),\n sessionStartedAt: session?.startedAt ?? now,\n rotatedAt: null,\n revoked: false\n });\n }\n\n async findByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n const doc = await this.collection.findOne({ tokenHash });\n return doc ? this.toInfo(doc) : null;\n }\n\n /** Superseded, not gone — see the Postgres service for why that matters. */\n async markRotated(tokenHash: string): Promise<void> {\n await this.collection.updateOne({ tokenHash }, { $set: { rotatedAt: new Date() } });\n }\n\n async revokeSession(sessionId: string): Promise<void> {\n await this.collection.updateMany(\n { sessionId },\n { $set: { revoked: true, rotatedAt: new Date() } }\n );\n }\n\n async prune(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.collection.deleteMany({\n uid,\n $or: [\n { expiresAt: { $lt: new Date() } },\n { sessionId, rotatedAt: { $ne: null, $lt: supersededBefore } }\n ]\n });\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n const user = await this.db.collection<MongoDoc>(\"rebase_users\").findOne({ id: uid });\n return user?.tokensValidAfter ? new Date(user.tokensValidAfter) : null;\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.db.collection<MongoDoc>(\"rebase_users\")\n .updateOne({ id: uid }, { $set: { tokensValidAfter: at } });\n }\n\n async deleteByHash(tokenHash: string): Promise<void> {\n await this.collection.deleteOne({ tokenHash });\n }\n\n async deleteAllForUser(uid: string): Promise<void> {\n await this.collection.deleteMany({ uid });\n }\n\n async listForUser(uid: string): Promise<RefreshTokenInfo[]> {\n const docs = await this.collection.find({ uid }).sort({ createdAt: 1 }).toArray();\n return docs.map(doc => this.toInfo(doc));\n }\n\n async deleteById(id: string, uid: string): Promise<void> {\n await this.collection.deleteOne({ id,\nuid });\n }\n}\n\nexport class MongoPasswordResetTokenService {\n constructor(private db: Db) {}\n\n private get collection() {\n return this.db.collection<MongoDoc>(\"rebase_password_reset_tokens\");\n }\n\n async createToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.collection.deleteMany({ uid,\nusedAt: null });\n\n await this.collection.insertOne({\n _id: new ObjectId().toString(),\n uid,\n tokenHash,\n expiresAt,\n usedAt: null\n });\n }\n\n async findValidByHash(tokenHash: string): Promise<{ uid: string; expiresAt: Date } | null> {\n const doc = await this.collection.findOne({\n tokenHash,\n usedAt: null,\n expiresAt: { $gt: new Date() }\n });\n\n if (!doc) return null;\n\n return {\n uid: doc.uid,\n expiresAt: new Date(doc.expiresAt)\n };\n }\n\n async markAsUsed(tokenHash: string): Promise<void> {\n await this.collection.updateOne(\n { tokenHash },\n { $set: { usedAt: new Date() } }\n );\n }\n\n async deleteAllForUser(uid: string): Promise<void> {\n await this.collection.deleteMany({ uid });\n }\n\n async deleteExpired(): Promise<void> {\n await this.collection.deleteMany({ expiresAt: { $lt: new Date() } });\n }\n}\n\nexport class MongoTokenRepository implements TokenRepository {\n private refreshTokenService: MongoRefreshTokenService;\n private passwordResetTokenService: MongoPasswordResetTokenService;\n\n constructor(private db: Db) {\n this.refreshTokenService = new MongoRefreshTokenService(db);\n this.passwordResetTokenService = new MongoPasswordResetTokenService(db);\n }\n\n async createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void> {\n await this.refreshTokenService.createToken(uid, tokenHash, expiresAt, userAgent, ipAddress, session);\n }\n\n async markRefreshTokenRotated(tokenHash: string): Promise<void> {\n await this.refreshTokenService.markRotated(tokenHash);\n }\n\n async revokeRefreshTokenSession(sessionId: string): Promise<void> {\n await this.refreshTokenService.revokeSession(sessionId);\n }\n\n async pruneRefreshTokens(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.refreshTokenService.prune(uid, sessionId, supersededBefore);\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n return this.refreshTokenService.getTokensValidAfter(uid);\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.refreshTokenService.setTokensValidAfter(uid, at);\n }\n\n async findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n return this.refreshTokenService.findByHash(tokenHash);\n }\n\n async deleteRefreshToken(tokenHash: string): Promise<void> {\n await this.refreshTokenService.deleteByHash(tokenHash);\n }\n\n async deleteAllRefreshTokensForUser(uid: string): Promise<void> {\n await this.refreshTokenService.deleteAllForUser(uid);\n }\n\n async listRefreshTokensForUser(uid: string): Promise<RefreshTokenInfo[]> {\n return this.refreshTokenService.listForUser(uid);\n }\n\n async deleteRefreshTokenById(id: string, uid: string): Promise<void> {\n await this.refreshTokenService.deleteById(id, uid);\n }\n\n async createPasswordResetToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.passwordResetTokenService.createToken(uid, tokenHash, expiresAt);\n }\n\n async findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null> {\n return this.passwordResetTokenService.findValidByHash(tokenHash);\n }\n\n async markPasswordResetTokenUsed(tokenHash: string): Promise<void> {\n await this.passwordResetTokenService.markAsUsed(tokenHash);\n }\n\n async deleteAllPasswordResetTokensForUser(uid: string): Promise<void> {\n await this.passwordResetTokenService.deleteAllForUser(uid);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.passwordResetTokenService.deleteExpired();\n }\n\n // Magic link token operations\n\n async createMagicLinkToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n const col = this.db.collection(\"magic_link_tokens\");\n await col.deleteMany({ uid, usedAt: null });\n await col.insertOne({ uid, tokenHash, expiresAt, usedAt: null, createdAt: new Date() });\n }\n\n async findValidMagicLinkToken(tokenHash: string): Promise<MagicLinkTokenInfo | null> {\n const col = this.db.collection(\"magic_link_tokens\");\n const doc = await col.findOne({ tokenHash, usedAt: null, expiresAt: { $gt: new Date() } });\n if (!doc) return null;\n return { uid: doc.uid as string, expiresAt: doc.expiresAt as Date };\n }\n\n async markMagicLinkTokenUsed(tokenHash: string): Promise<void> {\n const col = this.db.collection(\"magic_link_tokens\");\n await col.updateOne({ tokenHash }, { $set: { usedAt: new Date() } });\n }\n}\n\nexport class MongoAuthRepository implements AuthRepository {\n private userService: MongoUserService;\n private roleService: MongoRoleService;\n private tokenRepository: MongoTokenRepository;\n\n constructor(private db: Db) {\n this.userService = new MongoUserService(db);\n this.roleService = new MongoRoleService(db);\n this.tokenRepository = new MongoTokenRepository(db);\n }\n\n async createUser(data: CreateUserData): Promise<UserData> {\n return this.userService.createUser(data);\n }\n\n async getUserById(id: string): Promise<UserData | null> {\n return this.userService.getUserById(id);\n }\n\n async getUserByEmail(email: string): Promise<UserData | null> {\n return this.userService.getUserByEmail(email);\n }\n\n async getUserByIdentity(provider: string, providerId: string): Promise<UserData | null> {\n return this.userService.getUserByIdentity(provider, providerId);\n }\n\n async getUserIdentities(uid: string): Promise<UserIdentityData[]> {\n return this.userService.getUserIdentities(uid);\n }\n\n async linkUserIdentity(uid: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n return this.userService.linkUserIdentity(uid, provider, providerId, profileData);\n }\n\n async updateUser(id: string, data: Partial<Omit<CreateUserData, \"id\">>): Promise<UserData | null> {\n return this.userService.updateUser(id, data);\n }\n\n async deleteUser(id: string): Promise<void> {\n await this.userService.deleteUser(id);\n }\n\n async listUsers(): Promise<UserData[]> {\n return this.userService.listUsers();\n }\n\n async listUsersPaginated(options?: ListUsersOptions): Promise<PaginatedUsersResult> {\n return this.userService.listUsersPaginated(options);\n }\n\n async updatePassword(id: string, passwordHash: string): Promise<void> {\n await this.userService.updatePassword(id, passwordHash);\n }\n\n async setEmailVerified(id: string, verified: boolean): Promise<void> {\n await this.userService.setEmailVerified(id, verified);\n }\n\n async setVerificationToken(id: string, token: string | null): Promise<void> {\n await this.userService.setVerificationToken(id, token);\n }\n\n async getUserByVerificationToken(token: string): Promise<UserData | null> {\n return this.userService.getUserByVerificationToken(token);\n }\n\n async getUserRoles(uid: string): Promise<RoleData[]> {\n return this.userService.getUserRoles(uid);\n }\n\n async getUserRoleIds(uid: string): Promise<string[]> {\n return this.userService.getUserRoleIds(uid);\n }\n\n async setUserRoles(uid: string, roleIds: string[]): Promise<void> {\n await this.userService.setUserRoles(uid, roleIds);\n }\n\n async assignDefaultRole(uid: string, roleId: string): Promise<void> {\n await this.userService.assignDefaultRole(uid, roleId);\n }\n\n async getUserWithRoles(uid: string): Promise<{ user: UserData; roles: RoleData[] } | null> {\n return this.userService.getUserWithRoles(uid);\n }\n\n async getRoleById(id: string): Promise<RoleData | null> {\n return this.roleService.getRoleById(id);\n }\n\n async listRoles(): Promise<RoleData[]> {\n return this.roleService.listRoles();\n }\n\n async createRole(data: CreateRoleData): Promise<RoleData> {\n return this.roleService.createRole(data);\n }\n\n async updateRole(id: string, data: Partial<Omit<RoleData, \"id\">>): Promise<RoleData | null> {\n return this.roleService.updateRole(id, data);\n }\n\n async deleteRole(id: string): Promise<void> {\n await this.roleService.deleteRole(id);\n }\n\n async createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void> {\n await this.tokenRepository.createRefreshToken(uid, tokenHash, expiresAt, userAgent, ipAddress, session);\n }\n\n async markRefreshTokenRotated(tokenHash: string): Promise<void> {\n await this.tokenRepository.markRefreshTokenRotated(tokenHash);\n }\n\n async revokeRefreshTokenSession(sessionId: string): Promise<void> {\n await this.tokenRepository.revokeRefreshTokenSession(sessionId);\n }\n\n async pruneRefreshTokens(uid: string, sessionId: string, supersededBefore: Date): Promise<void> {\n await this.tokenRepository.pruneRefreshTokens(uid, sessionId, supersededBefore);\n }\n\n async getTokensValidAfter(uid: string): Promise<Date | null> {\n return this.tokenRepository.getTokensValidAfter(uid);\n }\n\n async setTokensValidAfter(uid: string, at: Date): Promise<void> {\n await this.tokenRepository.setTokensValidAfter(uid, at);\n }\n\n async findRefreshTokenByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n return this.tokenRepository.findRefreshTokenByHash(tokenHash);\n }\n\n async deleteRefreshToken(tokenHash: string): Promise<void> {\n await this.tokenRepository.deleteRefreshToken(tokenHash);\n }\n\n async deleteAllRefreshTokensForUser(uid: string): Promise<void> {\n await this.tokenRepository.deleteAllRefreshTokensForUser(uid);\n }\n\n async listRefreshTokensForUser(uid: string): Promise<RefreshTokenInfo[]> {\n return this.tokenRepository.listRefreshTokensForUser(uid);\n }\n\n async deleteRefreshTokenById(id: string, uid: string): Promise<void> {\n await this.tokenRepository.deleteRefreshTokenById(id, uid);\n }\n\n async createPasswordResetToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.tokenRepository.createPasswordResetToken(uid, tokenHash, expiresAt);\n }\n\n async findValidPasswordResetToken(tokenHash: string): Promise<PasswordResetTokenInfo | null> {\n return this.tokenRepository.findValidPasswordResetToken(tokenHash);\n }\n\n async markPasswordResetTokenUsed(tokenHash: string): Promise<void> {\n await this.tokenRepository.markPasswordResetTokenUsed(tokenHash);\n }\n\n async deleteAllPasswordResetTokensForUser(uid: string): Promise<void> {\n await this.tokenRepository.deleteAllPasswordResetTokensForUser(uid);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.tokenRepository.deleteExpiredTokens();\n }\n\n // Magic link token operations\n\n async createMagicLinkToken(uid: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.tokenRepository.createMagicLinkToken(uid, tokenHash, expiresAt);\n }\n\n async findValidMagicLinkToken(tokenHash: string): Promise<MagicLinkTokenInfo | null> {\n return this.tokenRepository.findValidMagicLinkToken(tokenHash);\n }\n\n async markMagicLinkTokenUsed(tokenHash: string): Promise<void> {\n await this.tokenRepository.markMagicLinkTokenUsed(tokenHash);\n }\n\n // MFA Repository Stub\n async createMfaFactor(uid: string, factorType: \"totp\", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async getMfaFactors(uid: string): Promise<MfaFactor[]> {\n return [];\n }\n async getMfaFactorById(factorId: string): Promise<(MfaFactor & { secretEncrypted: string }) | null> {\n return null;\n }\n async verifyMfaFactor(factorId: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async deleteMfaFactor(factorId: string, uid: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async createMfaChallenge(factorId: string, ipAddress?: string): Promise<MfaChallengeInfo> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async getMfaChallengeById(challengeId: string): Promise<MfaChallengeInfo | null> {\n return null;\n }\n async verifyMfaChallenge(challengeId: string): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async createRecoveryCodes(uid: string, codeHashes: string[]): Promise<void> {\n throw new Error(\"MFA is not implemented for MongoDB\");\n }\n async useRecoveryCode(uid: string, codeHash: string): Promise<boolean> {\n return false;\n }\n async getUnusedRecoveryCodeCount(uid: string): Promise<number> {\n return 0;\n }\n async deleteAllRecoveryCodes(uid: string): Promise<void> {\n // No-op\n }\n async hasVerifiedMfaFactors(uid: string): Promise<boolean> {\n return false;\n }\n}\n","import { Db, MongoClient } from \"mongodb\";\nimport type {\n BackendBootstrapper,\n InitializedDriver,\n BootstrappedAuth,\n DatabaseAdmin,\n HistoryConfig,\n RealtimeProvider,\n DataDriver,\n CollectionConfig\n} from \"@rebasepro/types\";\nimport { MongoDriver } from \"./services/MongoDriver\";\nimport { MongoRealtimeService } from \"./services/MongoRealtimeService\";\nimport { MongoCollectionRegistry } from \"./factory\";\nimport { MongoAuthRepository, MongoUserService, MongoRoleService } from \"./auth/services\";\nimport { logger } from \"@rebasepro/server\";\n\nexport interface MongoDriverConfig {\n connection: Db;\n client: MongoClient;\n}\n\nexport interface MongoDriverInternals {\n db: Db;\n client: MongoClient;\n registry: MongoCollectionRegistry;\n realtimeService: MongoRealtimeService;\n driver: MongoDriver;\n}\n\n/** Shape of the config object passed to `initializeDriver` by the coordinator. */\ninterface DriverInitConfig {\n collections?: CollectionConfig[];\n}\n\n/** Shape of the auth config passed to `initializeAuth`. */\ninterface AuthInitConfig {\n email?: import(\"@rebasepro/server\").EmailConfig;\n}\n\n\n\nexport function createMongoBootstrapper(mongoConfig: MongoDriverConfig): BackendBootstrapper {\n // Cached admin object, set during getAdmin() and used by initializeWebsockets\n let cachedAdmin: DatabaseAdmin | undefined;\n\n return {\n type: \"mongodb\",\n\n async initializeDriver(config: unknown): Promise<InitializedDriver> {\n const { collections } = config as DriverInitConfig;\n\n const registry = new MongoCollectionRegistry();\n if (collections) {\n collections.forEach(collection => registry.register(collection));\n }\n\n const db = mongoConfig.connection;\n const client = mongoConfig.client;\n\n // Verify connection\n try {\n await db.command({ ping: 1 });\n } catch (err) {\n logger.error(\"❌ Failed to connect to MongoDB\", { error: err });\n }\n\n const realtimeService = new MongoRealtimeService(db);\n const driver = new MongoDriver(db, realtimeService, undefined, registry);\n\n const internals: MongoDriverInternals = {\n db,\n client,\n registry,\n realtimeService,\n driver\n };\n\n return {\n driver,\n realtimeProvider: realtimeService,\n collectionRegistry: registry,\n internals\n };\n },\n\n async initializeAuth(config: unknown, driverResult: InitializedDriver): Promise<BootstrappedAuth | undefined> {\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const { ensureAuthCollectionsExist } = await import(\"./auth/ensure-collections\");\n await ensureAuthCollectionsExist(db);\n\n const { createEmailService } = await import(\"@rebasepro/server\");\n const authConfig = config as AuthInitConfig | undefined;\n let emailService: unknown;\n if (authConfig?.email) {\n emailService = createEmailService(authConfig.email);\n }\n\n const userService = new MongoUserService(db);\n const roleService = new MongoRoleService(db);\n const authRepository = new MongoAuthRepository(db);\n\n return {\n userService,\n roleService,\n authRepository,\n emailService\n };\n },\n\n async initializeHistory(config: HistoryConfig, driverResult: InitializedDriver): Promise<{ historyService: unknown } | undefined> {\n if (!config) return undefined;\n\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const { ensureHistoryCollectionExists } = await import(\"./history/ensure-history-collection\");\n await ensureHistoryCollectionExists(db);\n\n const { MongoHistoryService } = await import(\"./services/MongoHistoryService\");\n\n const retention = typeof config === \"object\" ? config.retention : undefined;\n const historyService = new MongoHistoryService(db, retention ? { ttlDays: retention } : undefined);\n\n return { historyService };\n },\n\n async initializeRealtime(_config: unknown, driverResult: InitializedDriver): Promise<RealtimeProvider | undefined> {\n const internals = driverResult.internals as MongoDriverInternals;\n return internals.realtimeService;\n },\n\n getAdmin(driverResult: InitializedDriver): DatabaseAdmin | undefined {\n const internals = driverResult.internals as MongoDriverInternals;\n const db = internals.db;\n\n const admin: DatabaseAdmin = {\n async executeAggregate(pipeline: Record<string, unknown>[]) {\n const firstStage = pipeline[0];\n const collName = (firstStage as { $from?: string })?.$from ?? \"__admin__\";\n const cursor = db.collection(collName).aggregate(pipeline);\n return await cursor.toArray() as Record<string, unknown>[];\n },\n async fetchCollectionStats(collectionName: string) {\n const stats = await db.command({ collStats: collectionName }) as { count: number; size: number };\n return { count: stats.count,\nsizeBytes: stats.size };\n },\n async fetchUnmappedTables(mappedPaths?: string[]) {\n const allCollections = await db.listCollections().toArray();\n const names = allCollections.map(c => c.name).filter(n => !n.startsWith(\"system.\"));\n if (!mappedPaths || mappedPaths.length === 0) return names;\n const mappedSet = new Set(mappedPaths.map(p => p.toLowerCase()));\n return names.filter(n => !mappedSet.has(n.toLowerCase()));\n },\n async fetchTableMetadata(collectionName: string) {\n const sample = await db.collection(collectionName).findOne();\n if (!sample) return { columns: [],\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n const columns = Object.entries(sample).map(([key, value]) => ({\n column_name: key,\n data_type: typeof value,\n udt_name: typeof value,\n is_nullable: \"YES\",\n column_default: null,\n character_maximum_length: null\n }));\n return { columns,\nforeignKeys: [],\njunctions: [],\npolicies: [] };\n }\n };\n\n cachedAdmin = admin;\n return admin;\n },\n\n mountRoutes() {},\n\n async initializeWebsockets(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown): Promise<void> {\n const { createMongoWebSocket } = await import(\"./websocket\");\n createMongoWebSocket(\n server as import(\"http\").Server,\n realtimeService as MongoRealtimeService,\n driver as MongoDriver,\n config as Record<string, unknown> | undefined,\n cachedAdmin\n );\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -3,30 +3,21 @@ import { Db, ObjectId } from "mongodb";
|
|
|
3
3
|
* Shallow comparison to find top-level keys that changed between two objects.
|
|
4
4
|
*/
|
|
5
5
|
export declare function findChangedFields(oldValues: Record<string, unknown>, newValues: Record<string, unknown>): string[] | null;
|
|
6
|
-
export
|
|
6
|
+
export type { RecordHistoryParams, HistoryRetentionConfig } from "@rebasepro/types";
|
|
7
|
+
import type { EntityHistoryEntry, RecordHistoryParams, HistoryRetentionConfig } from "@rebasepro/types";
|
|
8
|
+
/**
|
|
9
|
+
* A history entry as MongoDB stores it — not as it travels.
|
|
10
|
+
*
|
|
11
|
+
* Two fields differ from {@link EntityHistoryEntry}: the driver's own `_id`,
|
|
12
|
+
* and `updated_at` as a native `Date` so the retention query can compare it
|
|
13
|
+
* with `$lt`. Both of these used to be on an interface *named* `HistoryEntry`,
|
|
14
|
+
* which is also what `@rebasepro/server-postgres` called its wire shape — so
|
|
15
|
+
* the same name meant `string` in one driver and `Date` in the other.
|
|
16
|
+
*/
|
|
17
|
+
export interface MongoHistoryDocument extends Omit<EntityHistoryEntry, "updated_at"> {
|
|
7
18
|
_id?: ObjectId;
|
|
8
|
-
id: string;
|
|
9
|
-
table_name: string;
|
|
10
|
-
entity_id: string;
|
|
11
|
-
action: "create" | "update" | "delete";
|
|
12
|
-
changed_fields: string[] | null;
|
|
13
|
-
values: Record<string, unknown> | null;
|
|
14
|
-
previous_values: Record<string, unknown> | null;
|
|
15
|
-
updated_by: string | null;
|
|
16
19
|
updated_at: Date;
|
|
17
20
|
}
|
|
18
|
-
export interface RecordHistoryParams {
|
|
19
|
-
tableName: string;
|
|
20
|
-
id: string;
|
|
21
|
-
action: "create" | "update" | "delete";
|
|
22
|
-
values?: Record<string, unknown> | null;
|
|
23
|
-
previousValues?: Record<string, unknown> | null;
|
|
24
|
-
updatedBy?: string | null;
|
|
25
|
-
}
|
|
26
|
-
export interface HistoryRetentionConfig {
|
|
27
|
-
maxEntries: number;
|
|
28
|
-
ttlDays: number;
|
|
29
|
-
}
|
|
30
21
|
export declare class MongoHistoryService {
|
|
31
22
|
private db;
|
|
32
23
|
retention: HistoryRetentionConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoHistoryService.d.ts","sourceRoot":"","sources":["../../src/services/MongoHistoryService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0BvC;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,EAAE,GAAG,IAAI,CA8BjB;AAED,
|
|
1
|
+
{"version":3,"file":"MongoHistoryService.d.ts","sourceRoot":"","sources":["../../src/services/MongoHistoryService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0BvC;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,EAAE,GAAG,IAAI,CA8BjB;AAED,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAExG;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAC;IAChF,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,IAAI,CAAC;CACpB;AAOD,qBAAa,mBAAmB;IAIxB,OAAO,CAAC,EAAE;IAHP,SAAS,EAAE,sBAAsB,CAAC;gBAG7B,EAAE,EAAE,EAAE,EACd,SAAS,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC;IAMzC,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;YA0CjD,YAAY;CA+B7B"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/server-mongo",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"description": "MongoDB backend for Rebase",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"mongodb": "^7.3.0",
|
|
42
42
|
"ws": "^8.21.0",
|
|
43
|
-
"@rebasepro/common": "0.
|
|
44
|
-
"@rebasepro/
|
|
45
|
-
"@rebasepro/
|
|
43
|
+
"@rebasepro/common": "0.12.0",
|
|
44
|
+
"@rebasepro/utils": "0.12.0",
|
|
45
|
+
"@rebasepro/types": "0.12.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/jest": "^30.0.0",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"vite": "^8.0.16"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@rebasepro/server": "0.
|
|
58
|
+
"@rebasepro/server": "0.12.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"@rebasepro/server": {
|
|
@@ -62,33 +62,23 @@ export function findChangedFields(
|
|
|
62
62
|
return changed.length > 0 ? changed : null;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export
|
|
65
|
+
export type { RecordHistoryParams, HistoryRetentionConfig } from "@rebasepro/types";
|
|
66
|
+
import type { EntityHistoryEntry, RecordHistoryParams, HistoryRetentionConfig } from "@rebasepro/types";
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A history entry as MongoDB stores it — not as it travels.
|
|
70
|
+
*
|
|
71
|
+
* Two fields differ from {@link EntityHistoryEntry}: the driver's own `_id`,
|
|
72
|
+
* and `updated_at` as a native `Date` so the retention query can compare it
|
|
73
|
+
* with `$lt`. Both of these used to be on an interface *named* `HistoryEntry`,
|
|
74
|
+
* which is also what `@rebasepro/server-postgres` called its wire shape — so
|
|
75
|
+
* the same name meant `string` in one driver and `Date` in the other.
|
|
76
|
+
*/
|
|
77
|
+
export interface MongoHistoryDocument extends Omit<EntityHistoryEntry, "updated_at"> {
|
|
66
78
|
_id?: ObjectId;
|
|
67
|
-
id: string;
|
|
68
|
-
table_name: string;
|
|
69
|
-
entity_id: string;
|
|
70
|
-
action: "create" | "update" | "delete";
|
|
71
|
-
changed_fields: string[] | null;
|
|
72
|
-
values: Record<string, unknown> | null;
|
|
73
|
-
previous_values: Record<string, unknown> | null;
|
|
74
|
-
updated_by: string | null;
|
|
75
79
|
updated_at: Date;
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
export interface RecordHistoryParams {
|
|
79
|
-
tableName: string;
|
|
80
|
-
id: string;
|
|
81
|
-
action: "create" | "update" | "delete";
|
|
82
|
-
values?: Record<string, unknown> | null;
|
|
83
|
-
previousValues?: Record<string, unknown> | null;
|
|
84
|
-
updatedBy?: string | null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface HistoryRetentionConfig {
|
|
88
|
-
maxEntries: number;
|
|
89
|
-
ttlDays: number;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
82
|
const DEFAULT_RETENTION: HistoryRetentionConfig = {
|
|
93
83
|
maxEntries: 200,
|
|
94
84
|
ttlDays: 90
|
|
@@ -124,7 +114,7 @@ export class MongoHistoryService {
|
|
|
124
114
|
}
|
|
125
115
|
|
|
126
116
|
try {
|
|
127
|
-
const entry:
|
|
117
|
+
const entry: MongoHistoryDocument = {
|
|
128
118
|
id: new ObjectId().toString(),
|
|
129
119
|
table_name: tableName,
|
|
130
120
|
entity_id: String(id),
|