@rebasepro/server-postgresql 0.6.0 → 0.7.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.
Files changed (82) hide show
  1. package/package.json +24 -18
  2. package/src/PostgresBackendDriver.ts +65 -44
  3. package/src/PostgresBootstrapper.ts +49 -20
  4. package/src/auth/ensure-tables.ts +56 -1
  5. package/src/auth/services.ts +94 -1
  6. package/src/cli-errors.ts +162 -0
  7. package/src/cli-helpers.ts +183 -0
  8. package/src/cli.ts +198 -251
  9. package/src/data-transformer.ts +9 -1
  10. package/src/schema/auth-default-policies.ts +90 -0
  11. package/src/schema/auth-schema.ts +25 -2
  12. package/src/schema/doctor.ts +2 -4
  13. package/src/schema/generate-drizzle-schema-logic.ts +4 -3
  14. package/src/schema/generate-drizzle-schema.ts +3 -5
  15. package/src/schema/generate-postgres-ddl-logic.ts +524 -0
  16. package/src/schema/generate-postgres-ddl.ts +116 -0
  17. package/src/services/EntityPersistService.ts +18 -16
  18. package/src/services/entityService.ts +28 -3
  19. package/src/utils/pg-array-null-patch.ts +42 -0
  20. package/src/utils/pg-error-utils.ts +16 -0
  21. package/src/utils/table-classification.ts +16 -0
  22. package/src/websocket.ts +9 -0
  23. package/test/array-null-safety.test.ts +335 -0
  24. package/test/auth-default-policies.test.ts +89 -0
  25. package/test/cli-helpers-extended.test.ts +324 -0
  26. package/test/cli-helpers.test.ts +59 -0
  27. package/test/connection.test.ts +292 -0
  28. package/test/data-transformer.test.ts +53 -2
  29. package/test/databasePoolManager.test.ts +289 -0
  30. package/test/doctor-extended.test.ts +443 -0
  31. package/test/e2e/db-e2e.test.ts +293 -0
  32. package/test/e2e/pg-setup.ts +79 -0
  33. package/test/entity-persist-composite-keys.test.ts +451 -0
  34. package/test/generate-postgres-ddl-edge-cases.test.ts +716 -0
  35. package/test/generate-postgres-ddl.test.ts +300 -0
  36. package/test/mfa-service.test.ts +544 -0
  37. package/test/pg-array-null-patch.test.ts +65 -0
  38. package/test/pg-error-utils.test.ts +50 -1
  39. package/test/realtimeService-channels.test.ts +696 -0
  40. package/test/unmapped-tables-safety.test.ts +55 -342
  41. package/vite.config.ts +8 -6
  42. package/vitest.e2e.config.ts +10 -0
  43. package/build-errors.txt +0 -37
  44. package/dist/PostgresAdapter.d.ts +0 -6
  45. package/dist/PostgresBackendDriver.d.ts +0 -110
  46. package/dist/PostgresBootstrapper.d.ts +0 -46
  47. package/dist/auth/ensure-tables.d.ts +0 -10
  48. package/dist/auth/services.d.ts +0 -231
  49. package/dist/cli.d.ts +0 -1
  50. package/dist/collections/PostgresCollectionRegistry.d.ts +0 -47
  51. package/dist/connection.d.ts +0 -65
  52. package/dist/data-transformer.d.ts +0 -55
  53. package/dist/databasePoolManager.d.ts +0 -20
  54. package/dist/history/HistoryService.d.ts +0 -71
  55. package/dist/history/ensure-history-table.d.ts +0 -7
  56. package/dist/index.d.ts +0 -14
  57. package/dist/index.es.js +0 -10764
  58. package/dist/index.es.js.map +0 -1
  59. package/dist/index.umd.js +0 -11055
  60. package/dist/index.umd.js.map +0 -1
  61. package/dist/interfaces.d.ts +0 -18
  62. package/dist/schema/auth-schema.d.ts +0 -2149
  63. package/dist/schema/doctor-cli.d.ts +0 -2
  64. package/dist/schema/doctor.d.ts +0 -52
  65. package/dist/schema/generate-drizzle-schema-logic.d.ts +0 -2
  66. package/dist/schema/generate-drizzle-schema.d.ts +0 -1
  67. package/dist/schema/introspect-db-inference.d.ts +0 -5
  68. package/dist/schema/introspect-db-logic.d.ts +0 -118
  69. package/dist/schema/introspect-db.d.ts +0 -1
  70. package/dist/schema/test-schema.d.ts +0 -24
  71. package/dist/services/BranchService.d.ts +0 -47
  72. package/dist/services/EntityFetchService.d.ts +0 -214
  73. package/dist/services/EntityPersistService.d.ts +0 -40
  74. package/dist/services/RelationService.d.ts +0 -98
  75. package/dist/services/entity-helpers.d.ts +0 -38
  76. package/dist/services/entityService.d.ts +0 -110
  77. package/dist/services/index.d.ts +0 -4
  78. package/dist/services/realtimeService.d.ts +0 -220
  79. package/dist/types.d.ts +0 -3
  80. package/dist/utils/drizzle-conditions.d.ts +0 -138
  81. package/dist/utils/pg-error-utils.d.ts +0 -55
  82. package/dist/websocket.d.ts +0 -11
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.umd.js","names":["deepEqual"],"sources":["../src/connection.ts","../../types/src/rebase_context.tsx","../../types/src/types/entities.ts","../../types/src/types/chips.ts","../../types/src/types/properties.ts","../../types/src/types/collections.ts","../../types/src/types/relations.ts","../../types/src/types/locales.ts","../../types/src/types/entity_link_builder.ts","../../types/src/types/user_management_delegate.ts","../../types/src/types/entity_callbacks.ts","../../types/src/types/entity_overrides.tsx","../../types/src/types/export_import.ts","../../types/src/types/modify_collections.tsx","../../types/src/types/formex.ts","../../types/src/types/websockets.ts","../../types/src/types/backend.ts","../../types/src/types/translations.ts","../../types/src/types/plugins.tsx","../../types/src/types/builders.ts","../../types/src/types/slots.tsx","../../types/src/types/entity_actions.tsx","../../types/src/types/property_config.tsx","../../types/src/types/entity_views.tsx","../../types/src/types/data_source.ts","../../types/src/types/cron.ts","../../types/src/types/backend_hooks.ts","../../types/src/types/component_ref.ts","../../types/src/types/auth_adapter.ts","../../types/src/types/database_adapter.ts","../../types/src/types/breadcrumbs.ts","../../types/src/types/component_overrides.ts","../../types/src/types/index.ts","../../types/src/controllers/collection_registry.ts","../../types/src/controllers/analytics_controller.tsx","../../types/src/controllers/auth.tsx","../../types/src/controllers/data.ts","../../types/src/controllers/database_admin.ts","../../types/src/controllers/data_driver.ts","../../types/src/controllers/local_config_persistence.tsx","../../types/src/controllers/navigation.ts","../../types/src/controllers/effective_role.ts","../../types/src/controllers/storage.ts","../../types/src/controllers/email.ts","../../types/src/controllers/client.ts","../../types/src/controllers/customization_controller.tsx","../../types/src/controllers/side_entity_controller.tsx","../../types/src/controllers/side_dialogs_controller.tsx","../../types/src/controllers/dialogs_controller.tsx","../../types/src/controllers/snackbar.ts","../../types/src/controllers/registry.ts","../../types/src/controllers/index.ts","../../types/src/users/user.ts","../../types/src/users/index.ts","../../types/src/index.ts","../../common/src/util/common.ts","../../utils/src/strings.ts","../../../node_modules/.pnpm/object-hash@3.0.0/node_modules/object-hash/dist/object_hash.js","../../utils/src/objects.ts","../../utils/src/names.ts","../../common/src/util/entities.ts","../../common/src/util/enums.ts","../../common/src/util/relations.ts","../../common/src/util/resolutions.ts","../../common/src/util/permissions.ts","../../common/src/util/parent_references_from_path.ts","../../common/src/util/callbacks.ts","../../../node_modules/.pnpm/json-logic-js@2.0.5/node_modules/json-logic-js/logic.js","../../common/src/util/conditions.ts","../../../node_modules/.pnpm/fast-equals@6.0.0/node_modules/fast-equals/dist/es/index.mjs","../../common/src/collections/CollectionRegistry.ts","../../common/src/data/query_builder.ts","../../common/src/data/buildRebaseData.ts","../src/services/entity-helpers.ts","../src/utils/drizzle-conditions.ts","../src/data-transformer.ts","../src/services/RelationService.ts","../src/services/EntityFetchService.ts","../src/utils/pg-error-utils.ts","../src/services/EntityPersistService.ts","../src/services/entityService.ts","../src/services/BranchService.ts","../src/PostgresBackendDriver.ts","../src/databasePoolManager.ts","../src/schema/auth-schema.ts","../src/schema/generate-drizzle-schema-logic.ts","../src/schema/generate-drizzle-schema.ts","../src/services/realtimeService.ts","../src/websocket.ts","../src/collections/PostgresCollectionRegistry.ts","../src/auth/ensure-tables.ts","../src/auth/services.ts","../src/history/HistoryService.ts","../src/history/ensure-history-table.ts","../src/PostgresBootstrapper.ts","../src/PostgresAdapter.ts","../src/index.ts"],"sourcesContent":["import { Pool, PoolConfig } from \"pg\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/**\n * Configuration for the Postgres connection pool.\n *\n * Sensible defaults are provided for production Cloud Run / single-instance\n * deployments. Override via environment variables or explicit config.\n */\nexport interface PostgresPoolConfig {\n /** Maximum number of connections in the pool (default: 20) */\n max?: number;\n /** Close idle connections after this many ms (default: 30 000) */\n idleTimeoutMillis?: number;\n /** Abort connection attempts after this many ms (default: 10 000) */\n connectionTimeoutMillis?: number;\n /** Per-query timeout in ms (default: 30 000) */\n queryTimeout?: number;\n /** Per-statement timeout in ms (default: 30 000) */\n statementTimeout?: number;\n /** Enable TCP keep-alive (default: true) */\n keepAlive?: boolean;\n}\n\nconst DEFAULT_POOL: Required<PostgresPoolConfig> = {\n max: 20,\n idleTimeoutMillis: 30_000,\n connectionTimeoutMillis: 10_000,\n queryTimeout: 30_000,\n statementTimeout: 30_000,\n keepAlive: true\n};\n\n/**\n * Create a Drizzle-backed Postgres connection with a production-grade\n * connection pool.\n *\n * @param connectionString Postgres connection URL\n * @param schema Optional Drizzle schema for the relational API\n * @param poolConfig Optional pool tuning (merged over defaults)\n *\n * @returns `{ db, pool, connectionString }` — the `pool` is exposed so\n * callers can register shutdown hooks (`pool.end()`) or monitor\n * pool metrics.\n */\nexport function createPostgresDatabaseConnection(\n connectionString: string,\n schema?: Record<string, unknown>,\n poolConfig?: PostgresPoolConfig\n) {\n const opts = { ...DEFAULT_POOL,\n...poolConfig };\n\n const pgPoolConfig: PoolConfig = {\n connectionString,\n max: opts.max,\n idleTimeoutMillis: opts.idleTimeoutMillis,\n connectionTimeoutMillis: opts.connectionTimeoutMillis,\n query_timeout: opts.queryTimeout,\n statement_timeout: opts.statementTimeout,\n keepAlive: opts.keepAlive,\n keepAliveInitialDelayMillis: 0\n };\n\n const pool = new Pool(pgPoolConfig);\n\n // ── Pool event logging ────────────────────────────────────────────────\n // Uses console.* because the structured logger lives in server-core\n // (a separate package). The caller can replace these with the structured\n // logger if desired via pool.on() after creation.\n pool.on(\"error\", (err) => {\n logger.error(\"[pg-pool] Unexpected pool error\", { detail: err.message });\n if (err.message.includes(\"ETIMEDOUT\")) {\n logger.warn(\"[pg-pool] Connection timeout detected — pool will auto-retry\");\n }\n });\n\n // Create drizzle instance — pass schema when available to enable db.query relational API\n const db = schema ? drizzle(pool, { schema }) : drizzle(pool);\n\n return { db,\npool,\nconnectionString };\n}\n\n/**\n * Create a direct (non-pooled) connection for operations that require\n * session-level features incompatible with PgBouncer transaction mode,\n * such as LISTEN/NOTIFY, prepared statements, or advisory locks.\n *\n * Uses a smaller pool since this is only for specific use cases.\n */\nexport function createDirectDatabaseConnection(\n connectionString: string,\n schema?: Record<string, unknown>,\n poolConfig?: PostgresPoolConfig\n) {\n const opts = {\n ...DEFAULT_POOL,\n max: 5,\n ...poolConfig\n };\n\n const pgPoolConfig: PoolConfig = {\n connectionString,\n max: opts.max,\n idleTimeoutMillis: opts.idleTimeoutMillis,\n connectionTimeoutMillis: opts.connectionTimeoutMillis,\n query_timeout: opts.queryTimeout,\n statement_timeout: opts.statementTimeout,\n keepAlive: opts.keepAlive,\n keepAliveInitialDelayMillis: 0\n };\n\n const pool = new Pool(pgPoolConfig);\n\n pool.on(\"error\", (err) => {\n logger.error(\"[pg-direct-pool] Unexpected pool error\", { detail: err.message });\n });\n\n const db = schema ? drizzle(pool, { schema }) : drizzle(pool);\n\n return { db,\npool,\nconnectionString };\n}\n\n/**\n * Create a read-only connection for routing read queries to replicas.\n * Uses a moderate pool size since reads are distributed across replicas.\n */\nexport function createReadReplicaConnection(\n connectionString: string,\n schema?: Record<string, unknown>,\n poolConfig?: PostgresPoolConfig\n) {\n const opts = {\n ...DEFAULT_POOL,\n max: 10,\n ...poolConfig\n };\n\n const pgPoolConfig: PoolConfig = {\n connectionString,\n max: opts.max,\n idleTimeoutMillis: opts.idleTimeoutMillis,\n connectionTimeoutMillis: opts.connectionTimeoutMillis,\n query_timeout: opts.queryTimeout,\n statement_timeout: opts.statementTimeout,\n keepAlive: opts.keepAlive,\n keepAliveInitialDelayMillis: 0\n };\n\n const pool = new Pool(pgPoolConfig);\n\n pool.on(\"error\", (err) => {\n logger.error(\"[pg-replica-pool] Unexpected pool error\", { detail: err.message });\n });\n\n const db = schema ? drizzle(pool, { schema }) : drizzle(pool);\n\n return { db,\npool,\nconnectionString };\n}\n","import type { AnalyticsController } from \"./controllers/analytics_controller\";\nimport type { AuthController } from \"./controllers/auth\";\nimport type { StorageSource } from \"./controllers/storage\";\nimport type { UserConfigurationPersistence } from \"./controllers/local_config_persistence\";\nimport type { DatabaseAdmin } from \"./types/backend\";\nimport type { RebaseClient } from \"./controllers/client\";\n\nimport type { RebaseData } from \"./controllers/data\";\nimport type { User } from \"./users\";\n\n\n/**\n * Context that is provided to entity callbacks (hooks).\n * It contains only the dependencies that are available in both the frontend and the backend.\n * @group Hooks and utilities\n */\nexport type RebaseCallContext<USER extends User = User> = {\n\n /**\n * The Rebase client instance.\n * Available in all entity callbacks (beforeSave, afterSave, afterRead,\n * beforeDelete, afterDelete) and in CollectionActionsProps via context.\n * Use it to call backend functions, access data, storage, etc.\n *\n * @example\n * // In a beforeSave callback:\n * const result = await context.client.functions.invoke('my-function', { ... });\n *\n * @example\n * // In a CollectionAction component:\n * const { client } = props.context;\n * const result = await client.functions.invoke('extract-job', { url });\n */\n client: RebaseClient;\n\n /**\n * Unified data access — `context.data.products.create(...)`.\n * Access any collection as a dynamic property.\n */\n data: RebaseData;\n\n /**\n * Used storage implementation\n */\n storageSource: StorageSource;\n\n /**\n * Set by the backend when callbacks are executed on the server.\n */\n user?: USER;\n}\n\n/**\n * Context that includes the internal controllers and contexts used by the app.\n * Some controllers and context included in this context can be accessed\n * directly from their respective hooks.\n * @group Hooks and utilities\n * @see useRebaseContext\n */\nexport type RebaseContext<USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>> = RebaseCallContext<USER> & {\n\n authController: AuthControllerType;\n\n /**\n * Controller mapping strings to collections\n */\n collectionRegistryController?: import(\"./controllers/collection_registry\").CollectionRegistryController;\n\n /**\n * Controller for navigation state\n */\n navigationStateController?: import(\"./controllers/navigation\").NavigationStateController;\n\n /**\n * Controller for side dialogs (side sheets)\n */\n sideDialogsController?: import(\"./controllers/side_dialogs_controller\").SideDialogsController;\n\n /**\n * Controller to open the side dialog displaying entity forms\n */\n sideEntityController?: import(\"./controllers/side_entity_controller\").SideEntityController;\n\n /**\n * Controller resolving URLs in the CMS\n */\n urlController?: import(\"./controllers/navigation\").UrlController;\n\n /**\n * Controller to handle simple confirmation and alert dialogs\n */\n dialogsController?: import(\"./controllers/dialogs_controller\").DialogsController;\n\n /**\n * Controller for CMS customization\n */\n customizationController?: import(\"./controllers/customization_controller\").CustomizationController;\n\n /**\n * Controller for effective role\n */\n effectiveRoleController?: { effectiveRole: string | null, setEffectiveRole: (role: string | null) => void };\n\n /**\n * Use this controller to access data stored in the browser for the user\n */\n userConfigPersistence?: UserConfigurationPersistence;\n\n /**\n * Callback to send analytics events\n */\n analyticsController?: AnalyticsController;\n\n\n /**\n * Administrative database operations (SQL, schema discovery).\n * Only available in developer/admin contexts.\n */\n databaseAdmin?: DatabaseAdmin;\n\n /**\n * Controller for snackbars\n */\n snackbarController?: import(\"./controllers/snackbar\").SnackbarController;\n\n};\n","/**\n * New or existing status\n * @group Models\n */\nexport type EntityStatus = \"new\" | \"existing\" | \"copy\";\n\n/**\n * Representation of an entity fetched from the driver\n * @group Models\n */\nexport interface Entity<M extends Record<string, unknown> = Record<string, unknown>> {\n\n /**\n * ID of the entity\n */\n id: string | number;\n\n /**\n * A string representing the path of the referenced document (relative\n * to the root of the database).\n */\n path: string;\n\n /**\n * Current values\n */\n values: EntityValues<M>;\n\n /**\n * Which driver this entity belongs to (e.g., 'postgres', 'firestore').\n * If not specified, the default driver is assumed.\n */\n driver?: string;\n\n /**\n * Which database within the driver (e.g., for Firestore multi-database).\n * If not specified, the default database of the driver is used.\n */\n databaseId?: string;\n}\n\n/**\n * This type represents a record of key value pairs as described in an\n * entity collection.\n * @group Models\n */\nexport type EntityValues<M extends Record<string, unknown>> = M;\n\n/**\n * Props for creating an EntityReference\n */\nexport interface EntityReferenceProps {\n /** ID of the entity */\n id: string;\n /** Path of the collection (relative to the root of the database) */\n path: string;\n /** Which driver (e.g., 'postgres', 'firestore'). Defaults to \"(default)\" */\n driver?: string;\n /** Which database within the driver. Defaults to \"(default)\" */\n databaseId?: string;\n}\n\n/**\n * Class used to create a reference to an entity in a different path.\n *\n * @example\n * // Simple reference (most common case - single driver, single db)\n * new EntityReference({ id: \"123\", path: \"users\" })\n *\n * // Reference to a different driver (e.g., Firestore)\n * new EntityReference({ id: \"123\", path: \"analytics\", driver: \"firestore\" })\n *\n * // Reference to a specific database within a driver\n * new EntityReference({ id: \"123\", path: \"orders\", driver: \"postgres\", databaseId: \"orders_db\" })\n */\nexport class EntityReference {\n\n readonly __type = \"reference\";\n /**\n * ID of the entity\n */\n readonly id: string;\n /**\n * A string representing the path of the referenced document (relative\n * to the root of the database).\n */\n readonly path: string;\n\n /**\n * Which driver (e.g., 'postgres', 'firestore').\n * Defaults to \"(default)\" if not specified.\n */\n readonly driver?: string;\n\n /**\n * Which database within the driver.\n * Defaults to \"(default)\" if not specified.\n */\n readonly databaseId?: string;\n\n /**\n * Create a reference to an entity.\n *\n * @example\n * // Simple reference (most common case)\n * new EntityReference({ id: \"123\", path: \"users\" })\n *\n * // With driver\n * new EntityReference({ id: \"123\", path: \"analytics\", driver: \"firestore\" })\n */\n constructor(props: EntityReferenceProps) {\n this.id = props.id;\n this.path = props.path;\n this.driver = props.driver;\n this.databaseId = props.databaseId;\n }\n\n get pathWithId() {\n return `${this.path}/${this.id}`;\n }\n\n /**\n * Get the full path including driver and database prefixes if specified.\n * For the common case (single driver, single db), this just returns pathWithId.\n */\n get fullPath() {\n const parts: string[] = [];\n\n // Add driver prefix if not default\n if (this.driver && this.driver !== \"(default)\") {\n parts.push(this.driver);\n }\n\n // Add database prefix if specified\n if (this.databaseId && this.databaseId !== \"(default)\") {\n parts.push(this.databaseId);\n }\n\n if (parts.length > 0) {\n return `${parts.join(\":\")}:::${this.path}/${this.id}`;\n }\n return this.pathWithId;\n }\n\n isEntityReference() {\n return true;\n }\n}\n\n/**\n * Class used to create a reference to an entity in a different path\n */\nexport class EntityRelation {\n\n readonly __type = \"relation\";\n /**\n * ID of the entity\n */\n readonly id: string | number;\n /**\n * A string representing the path of the referenced document (relative\n * to the root of the database).\n */\n readonly path: string;\n\n /**\n * Pre-fetched data payload to eliminate N+1 queries.\n * When present, clients can use this directly instead of fetching.\n */\n readonly data?: Entity;\n\n constructor(id: string | number, path: string, data?: Entity) {\n this.id = id;\n this.path = path;\n this.data = data;\n }\n\n get pathWithId() {\n return `${this.path}/${this.id}`;\n }\n\n isEntityReference() {\n return false;\n }\n\n isEntityRelation() {\n return true;\n }\n}\n\nexport class GeoPoint {\n\n /**\n * The latitude of this GeoPoint instance.\n */\n readonly latitude: number;\n /**\n * The longitude of this GeoPoint instance.\n */\n readonly longitude: number;\n\n constructor(latitude: number, longitude: number) {\n this.latitude = latitude;\n this.longitude = longitude;\n }\n}\n\nexport class Vector {\n readonly value: number[];\n\n constructor(value: number[]) {\n this.value = value;\n }\n}\n","export type ColorScheme = {\n color: string;\n text: string;\n}\n\nexport type ColorKey =\n | \"blue\"\n | \"cyan\"\n | \"teal\"\n | \"green\"\n | \"yellow\"\n | \"orange\"\n | \"red\"\n | \"pink\"\n | \"purple\"\n | \"gray\"\n | \"indigo\"\n | \"violet\"\n | \"fuchsia\"\n | \"rose\"\n | \"emerald\";\n","import type { ComponentRef } from \"./component_ref\";\n\nimport type { Entity, EntityReference, EntityRelation, EntityValues, GeoPoint, Vector } from \"./entities\";\nimport type { JoinStep, OnAction, Relation } from \"./relations\";\nimport type { EntityCollection, FilterValues } from \"./collections\";\nimport type { ColorKey, ColorScheme } from \"./chips\";\nimport type { AuthController } from \"../controllers/auth\";\nimport type { EntityAfterReadProps, EntityBeforeSaveProps } from \"./entity_callbacks\";\nimport type { User } from \"../users\";\n\n/**\n * Callbacks/Hooks for individual property fields\n * @group Entity properties\n */\nexport type PropertyCallbacks<T = unknown, M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {\n /**\n * Callback used after fetching data, to transform the value before rendering\n */\n afterRead?(props: Omit<EntityAfterReadProps<M, USER>, \"entity\"> & {\n value: T;\n entity: Entity<M> | undefined;\n }): Promise<T> | T;\n\n /**\n * Callback used before saving, after validation.\n * You can modify the value before it's saved.\n */\n beforeSave?(props: Omit<EntityBeforeSaveProps<M, USER>, \"values\"> & {\n value: T;\n previousValue: T | undefined;\n values: Partial<M>;\n }): Promise<T> | T;\n}\n\n/**\n * @group Entity properties\n */\nexport type DataType =\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"geopoint\"\n | \"reference\"\n | \"relation\"\n | \"array\"\n | \"map\"\n | \"vector\"\n | \"binary\";\n\nexport type Property =\n | StringProperty\n | NumberProperty\n | BooleanProperty\n | DateProperty\n | GeopointProperty\n | ReferenceProperty\n | RelationProperty\n | ArrayProperty\n | MapProperty\n | VectorProperty\n | BinaryProperty;\n\nexport type Properties = {\n [key: string]: Property;\n};\n\nexport type PostgresProperty = Exclude<Property, ReferenceProperty>;\nexport type PostgresProperties = {\n [key: string]: PostgresProperty;\n};\n\nexport type FirebaseProperty = Exclude<Property, RelationProperty>;\nexport type FirebaseProperties = {\n [key: string]: FirebaseProperty;\n};\n\n/**\n * A helper type to infer the underlying data type from a Property definition.\n * This is the core of the type inference system.\n */\nexport type InferPropertyType<P extends Property> =\n P extends StringProperty ? string :\n P extends NumberProperty ? number :\n P extends BooleanProperty ? boolean :\n P extends DateProperty ? Date :\n P extends GeopointProperty ? GeoPoint :\n P extends ReferenceProperty ? EntityReference :\n P extends RelationProperty ? EntityRelation | EntityRelation[] :\n P extends ArrayProperty ? (P[\"of\"] extends Property ? InferPropertyType<P[\"of\"]>[] : unknown[]) :\n P extends MapProperty ? (P[\"properties\"] extends Properties ? InferEntityType<P[\"properties\"]> : Record<string, unknown>) :\n P extends VectorProperty ? Vector :\n P extends BinaryProperty ? string :\n never;\n\n/**\n * Helper type that determines whether a property is required.\n * Uses direct structural matching against `{ validation: { required: true } }`\n * (without the optional marker on `validation`), which correctly narrows\n * literal `true` while treating widened `boolean` as not-required.\n */\ntype IsRequired<P extends Property> = P extends { validation: { required: true } } ? true : false;\n\n/**\n * Extract keys from Properties where the property is required.\n */\ntype RequiredPropertyKeys<P extends Properties> = {\n [K in keyof P]: IsRequired<P[K]> extends true ? K : never;\n}[keyof P];\n\n/**\n * Extract keys from Properties where the property is optional.\n */\ntype OptionalPropertyKeys<P extends Properties> = {\n [K in keyof P]: IsRequired<P[K]> extends true ? never : K;\n}[keyof P];\n\n/**\n * A generic type that converts a `Properties` schema definition into a corresponding\n * TypeScript entity type. It correctly handles required and optional properties.\n *\n * A property is considered required when it has `validation: { required: true }`.\n * The `true` must be a literal type — if `required` is typed as `boolean`,\n * the property will be treated as optional (use `as const` for literal inference).\n *\n * @example\n * const productSchema = {\n * name: { type: 'string', validation: { required: true } },\n * price: { type: 'number' }\n * } as const satisfies Properties;\n * type Product = InferEntityType<typeof productSchema>;\n * // Result: { name: string; price?: number; }\n */\nexport type InferEntityType<P extends Properties> = {\n -readonly [K in RequiredPropertyKeys<P>]: InferPropertyType<P[K]>;\n} & {\n -readonly [K in OptionalPropertyKeys<P>]?: InferPropertyType<P[K]>;\n};\n\n/**\n * Interface including all common properties of a CMS property.\n * @group Entity properties\n */\nexport interface BaseUIConfig<CustomProps = unknown> {\n columnWidth?: number;\n hideFromCollection?: boolean;\n readOnly?: boolean;\n disabled?: boolean | PropertyDisabledConfig;\n widthPercentage?: number;\n customProps?: CustomProps;\n Field?: ComponentRef<any>;\n Preview?: ComponentRef<any>;\n}\n\nexport interface BaseProperty<CustomProps = unknown> {\n ui?: BaseUIConfig<CustomProps>;\n /**\n * Property name (e.g. Product)\n */\n name: string;\n\n /**\n * Property description, always displayed under the field\n */\n description?: string;\n\n /**\n * You can use this prop to reuse a property that has been defined\n * in the top level of the CMS in the prop `fields`.\n * All the configuration will be taken from the inherited config, and\n * overwritten by the current property config.\n */\n propertyConfig?: string;\n\n /**\n * Explicit database column name. When set, this value is used as-is\n * for the SQL column name, bypassing any snake_case conversion of\n * the property key.\n *\n * This is automatically populated by `rebase schema introspect`\n * to guarantee an exact match with the live database schema.\n *\n * For manually-authored collections you can omit this — the framework\n * will derive the column name from the property key via `toSnakeCase()`.\n */\n columnName?: string;\n\n /**\n * Rules for validating this property\n */\n validation?: PropertyValidationSchema;\n\n /**\n * This value will be set by default for new entities.\n */\n defaultValue?: unknown;\n\n /**\n * Use this to define dynamic properties that change based on certain conditions\n * or on the entity's values. For example, you can make a field read-only if\n * another field has a certain value.\n * This function receives the same props as a `PropertyBuilder` and should return a partial `Property` object.\n */\n dynamicProps?: (props: PropertyBuilderProps) => Partial<Property>;\n\n /**\n * Declarative conditions for dynamic property behavior using JSON Logic.\n *\n * An alternative to PropertyBuilder functions that can be:\n * - Stored in the database as JSON\n * - Edited via the collection editor UI\n * - Evaluated at runtime like property builders\n *\n * @see PropertyConditions for available condition options\n * @see https://jsonlogic.com/ for JSON Logic syntax\n */\n conditions?: PropertyConditions;\n\n /**\n * Callbacks/Hooks for this property field to transform and sanitize data during its lifecycle.\n */\n callbacks?: PropertyCallbacks;\n\n}\n\n/**\n * @group Entity properties\n */\nexport interface StringUIConfig extends BaseUIConfig {\n multiline?: boolean;\n markdown?: boolean;\n previewAsTag?: boolean;\n clearable?: boolean;\n url?: boolean | PreviewType;\n}\n\nexport interface StringProperty extends BaseProperty {\n ui?: StringUIConfig;\n type: \"string\";\n /**\n * Optional database column type. If not set, it defaults to `varchar` or `uuid` depending on `isId` configuration.\n * Use `text` for strings with unbound length, `char` for fixed-length strings, or `varchar` for variable-length strings with a limit.\n */\n columnType?: \"varchar\" | \"text\" | \"char\" | \"uuid\";\n /**\n * Rules for validating this property\n */\n validation?: StringPropertyValidationSchema;\n /**\n * Marks this field as a Primary Key / Unique Identifier.\n * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.\n * Drizzle append: `.primaryKey()`\n * UI behavior: Field value cannot be changed after creation.\n *\n * You can set this to `\"manual\"` for a user-defined ID, or specify a generation strategy:\n * 'uuid' -> Drizzle `.defaultRandom()` (Postgres gen_random_uuid())\n * 'cuid' -> Drizzle `.default(sql\\`cuid()\\`)`\n * Or any other random string to act as a raw SQL default expression: e.g. `nanoid()`\n *\n * On the UI side, the field automatically gets disabled on new entities if a string strategy is provided.\n */\n isId?: boolean | \"manual\" | \"uuid\" | \"cuid\" | string;\n /**\n * You can use the enum values providing a map of possible\n * exclusive values the property can take, mapped to the label that it is\n * displayed in the dropdown. You can use a simple object with the format\n * `value` => `label`, or with the format `value` => `EnumValueConfig` if you\n * need extra customization, (like disabling specific options or assigning\n * colors). If you need to ensure the order of the elements, you can pass\n * a `Map` instead of a plain object.\n *\n */\n enum?: EnumValues;\n /**\n * Is this string property long enough so it should be displayed in\n * a multiple line field. Defaults to false. If set to true,\n * the number of lines adapts to the content\n */\n multiline?: boolean;\n /**\n * Should this string property be displayed as a markdown field. If true,\n * the field is rendered as a text editors that supports markdown highlight\n * syntax. It also includes a preview of the result.\n */\n markdown?: boolean;\n /**\n * You can specify a `Storage` configuration. It is used to\n * indicate that this string refers to a path in your storage provider.\n */\n storage?: StorageConfig;\n\n /**\n * This property is used to indicate that the string is a user ID, and\n * it will be rendered as a user picker.\n * Note that the user ID needs to be the one used in your authentication\n * provider, e.g. Firebase Auth.\n * You can also use a property builder to specify the user path dynamically\n * based on other values of the entity.\n */\n userSelect?: boolean;\n\n /**\n * If the value of this property is a URL, you can set this flag to true\n * to add a link, or one of the supported media types to render a preview\n */\n url?: boolean | PreviewType;\n /**\n * Does this field include an email\n */\n email?: boolean;\n /**\n * Should this string be rendered as a tag instead of just text.\n */\n previewAsTag?: boolean;\n\n /**\n * You can use this property (a string) to behave as a reference to another\n * collection. The stored value is the ID of the entity in the\n * collection, and the `path` prop is used to\n * define the collection this reference points to.\n */\n reference?: ReferenceProperty;\n}\n\n/**\n * @group Entity properties\n */\nexport interface NumberUIConfig extends BaseUIConfig {\n clearable?: boolean;\n}\n\nexport interface NumberProperty extends BaseProperty {\n ui?: NumberUIConfig;\n type: \"number\";\n /**\n * Optional database column type. Allows specifying exact database numeric types.\n * If not provided, integer fields (where validation.integer is true or isId is true) default to `integer`, others to `numeric`.\n */\n columnType?: \"integer\" | \"real\" | \"double precision\" | \"numeric\" | \"bigint\" | \"serial\" | \"bigserial\";\n /**\n * Rules for validating this property\n */\n validation?: NumberPropertyValidationSchema;\n /**\n * Marks this field as a Primary Key / Unique Identifier.\n * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.\n * Drizzle append: `.primaryKey()`\n * UI behavior: Field value cannot be changed after creation.\n *\n * You can set this to `\"manual\"` for a user-defined ID, or specify a generation strategy:\n * 'increment' -> PostgreSQL `GENERATED BY DEFAULT AS IDENTITY` or auto-incrementing integer.\n * Or any other random string to act as a raw SQL default expression.\n */\n isId?: boolean | \"manual\" | \"increment\" | string;\n /**\n * You can use the enum values providing a map of possible\n * exclusive values the property can take, mapped to the label that it is\n * displayed in the dropdown.\n */\n enum?: EnumValues;\n\n}\n\n/**\n * @group Entity properties\n */\nexport interface BooleanProperty extends BaseProperty {\n ui?: BaseUIConfig;\n type: \"boolean\";\n /**\n * Rules for validating this property\n */\n validation?: PropertyValidationSchema;\n}\n\n/**\n * @group Entity properties\n */\nexport interface VectorUIConfig extends BaseUIConfig {\n clearable?: boolean;\n}\n\nexport interface VectorProperty extends BaseProperty {\n ui?: VectorUIConfig;\n type: \"vector\";\n dimensions: number;\n validation?: PropertyValidationSchema;\n}\n\n/**\n * @group Entity properties\n */\nexport interface BinaryProperty extends BaseProperty {\n type: \"binary\";\n validation?: PropertyValidationSchema;\n}\n\n/**\n * @group Entity properties\n */\nexport interface DateUIConfig extends BaseUIConfig {\n clearable?: boolean;\n}\n\nexport interface DateProperty extends BaseProperty {\n ui?: DateUIConfig;\n type: \"date\";\n /**\n * Optional database column type. If not set, defaults to `timestamp` with timezone.\n */\n columnType?: \"timestamp\" | \"date\" | \"time\";\n /**\n * Rules for validating this property\n */\n validation?: DatePropertyValidationSchema;\n /**\n * Set the granularity of the field to a date or date + time.\n * Defaults to `date_time`.\n *\n */\n mode?: \"date\" | \"date_time\";\n /**\n * Timezone string to evaluate the date in.\n */\n timezone?: string;\n /**\n * If this flag is set to `on_create` or `on_update` this timestamp is\n * updated automatically on creation of the entity only or on every\n * update (including creation). Useful for creating `created_on` or\n * `updated_on` fields\n */\n autoValue?: \"on_create\" | \"on_update\";\n /**\n * Add an icon to clear the value and set it to `null`. Defaults to `false`\n */\n clearable?: boolean;\n}\n\n/**\n * @group Entity properties\n */\nexport interface GeopointProperty extends BaseProperty {\n ui?: BaseUIConfig;\n type: \"geopoint\";\n /**\n * Rules for validating this property\n */\n validation?: PropertyValidationSchema;\n}\n\n/**\n * @group Entity properties\n */\nexport interface ReferenceUIConfig extends BaseUIConfig {\n previewProperties?: string[];\n}\n\nexport interface ReferenceProperty extends BaseProperty {\n ui?: ReferenceUIConfig;\n type: \"reference\";\n /**\n * Marks this field as a Primary Key / Unique Identifier.\n * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.\n * Drizzle append: `.primaryKey()`\n * UI behavior: Field value cannot be changed after creation.\n */\n isId?: boolean;\n /**\n * Absolute collection path of the collection this reference points to.\n * The collection of the entity is inferred based on the root navigation, so\n * the filters and search delegate existing there are applied to this view\n * as well.\n * You can leave this prop undefined if the path is not yet know, e.g.\n * you are using a property builder and the path depends on a different\n * property.\n */\n path?: string;\n /**\n * Allow selection of entities that pass the given filter only.\n * e.g. `fixedFilter: { age: [\">=\", 18] }`\n */\n fixedFilter?: FilterValues<string>;\n\n /**\n * Should the reference include the ID of the entity. Defaults to `true`\n */\n includeId?: boolean;\n /**\n * Should the reference include a link to the entity (open the entity details). Defaults to `true`\n */\n includeEntityLink?: boolean;\n}\n\n/**\n * @group Entity properties\n */\nexport interface RelationUIConfig extends BaseUIConfig {\n previewProperties?: string[];\n widget?: \"select\" | \"dialog\";\n}\n\nexport interface RelationProperty extends BaseProperty {\n ui?: RelationUIConfig;\n type: \"relation\";\n /**\n * Marks this field as a Primary Key / Unique Identifier.\n * Framework behavior: Auto-maps to `collection.primaryKeys` internally if not explicitly set.\n * Drizzle append: `.primaryKey()`\n * UI behavior: Field value cannot be changed after creation.\n */\n isId?: boolean;\n\n // ─── Inline relation config ───\n // Define the relation directly on the property. The framework automatically\n // extracts these into the collection's `relations[]` at normalization time.\n // You no longer need a separate `relations[]` entry for properties.\n\n /**\n * The target collection this relation points to.\n * When set, the framework treats this property as a self-contained relation\n * definition and no separate `relations[]` entry is needed.\n */\n target?: string | (() => EntityCollection | string);\n\n /**\n * Whether this property references one or many records.\n * Defaults to `\"one\"`.\n */\n cardinality?: \"one\" | \"many\";\n\n /**\n * Which side owns the persistence for this relationship.\n * - `\"owning\"`: The foreign key (for one-to-one) or junction table (for many-to-many) is on this collection.\n * - `\"inverse\"`: The foreign key is on the target collection's table.\n * Defaults to `\"owning\"`.\n */\n direction?: \"owning\" | \"inverse\";\n\n /**\n * The name of the corresponding relation on the target collection.\n * Used for inverse relations to locate the owning side.\n */\n inverseRelationName?: string;\n\n /**\n * Column on THIS table that stores the foreign key to the target.\n * Required when `direction` is `\"owning\"` and `cardinality` is `\"one\"`.\n * Auto-inferred if not set.\n * @example \"author_id\"\n */\n localKey?: string;\n\n /**\n * Column on the TARGET table that stores the foreign key back to this entity.\n * Required when `direction` is `\"inverse\"`.\n * Auto-inferred if not set.\n * @example \"post_id\"\n */\n foreignKeyOnTarget?: string;\n\n /**\n * Junction table configuration for many-to-many relationships.\n * Required when `cardinality` is `\"many\"` and `direction` is `\"owning\"`.\n * Auto-inferred if not set.\n */\n through?: {\n table: string;\n sourceColumn: string;\n targetColumn: string;\n };\n\n /**\n * Explicit, ordered join path for advanced multi-hop relations.\n * When set, overrides `localKey`, `foreignKeyOnTarget`, and `through`.\n */\n joinPath?: JoinStep[];\n\n /**\n * Cascade action on update.\n */\n onUpdate?: OnAction;\n\n /**\n * Cascade action on delete.\n */\n onDelete?: OnAction;\n\n /**\n * Overrides applied to the target collection when rendered as a subcollection tab.\n */\n overrides?: Partial<EntityCollection>;\n\n // ─── Framework-managed fields ───\n\n /**\n * Optional name for this relation. Defaults to the property key at runtime.\n * Only needed when the relation name should differ from the property key,\n * or for backward compatibility with existing `relations[]` entries.\n */\n relationName?: string;\n\n /**\n * The resolved relation object, populated by the framework at normalization time.\n * **Do not set manually** — it is computed from the inline fields above\n * or looked up from the collection's `relations[]` array.\n */\n relation?: Relation;\n\n // ─── UI configuration ───\n\n /**\n * Allow selection of entities that pass the given filter only.\n * e.g. `fixedFilter: { age: [\">=\", 18] }`\n */\n fixedFilter?: FilterValues<string>;\n\n /**\n * Should the reference include the ID of the entity. Defaults to `true`\n */\n includeId?: boolean;\n /**\n * Should the reference include a link to the entity (open the entity details). Defaults to `true`\n */\n includeEntityLink?: boolean;\n\n /**\n * Choose the widget to use for selecting the relation.\n * Defaults to `select`.\n */\n widget?: \"select\" | \"dialog\";\n}\n\n/**\n * @group Entity properties\n */\nexport interface ArrayUIConfig extends BaseUIConfig {\n expanded?: boolean;\n minimalistView?: boolean;\n}\n\nexport interface ArrayProperty extends BaseProperty {\n ui?: ArrayUIConfig;\n type: \"array\";\n /**\n * Optional database column type. By default, maps to a native Postgres array\n * (e.g. `text[]`, `integer[]`/`numeric[]`, `boolean[]`) if the element type\n * is a primitive, otherwise defaults to `jsonb`.\n */\n columnType?: \"json\" | \"jsonb\" | \"text[]\" | \"integer[]\" | \"boolean[]\" | \"numeric[]\";\n /**\n * The property of this array.\n * You can specify any property (except another Array property)\n * You can leave this field empty only if you are providing a custom field,\n * or using the `oneOf` prop, otherwise an error will be thrown.\n */\n of?: Property | Property[];\n /**\n * Use this field if you would like to have an array of typed objects.\n * It is useful if you need to have values of different types in the same\n * array.\n * Each entry of the array is an object with the shape:\n * ```\n * { type: \"YOUR_TYPE\", value: \"YOUR_VALUE\"}\n * ```\n * Note that you can use any property so `value` can take any value (strings,\n * numbers, array, objects...)\n * You can customise the `type` and `value` fields to suit your needs.\n *\n * An example use case for this feature may be a blog entry, where you have\n * images and text blocks using markdown.\n */\n oneOf?: {\n /**\n * Record of properties, where the key is the `type` and the value\n * is the corresponding property\n */\n properties: Properties;\n /**\n * Order in which the properties are displayed.\n * If you are specifying your collection as code, the order is the same as the\n * one you define in `properties`, and you don't need to specify this prop.\n */\n propertiesOrder?: string[];\n /**\n * Name of the field to use as the discriminator for type\n * Defaults to `type`\n */\n typeField?: string;\n /**\n * Name of the field to use as the value\n * Defaults to `value`\n */\n valueField?: string;\n };\n /**\n * Rules for validating this property\n */\n validation?: ArrayPropertyValidationSchema;\n\n /**\n * Can the elements in this array be reordered. Defaults to `true`.\n * This prop has no effect if `disabled` is set to true.\n */\n sortable?: boolean;\n /**\n * Can the elements in this array be added. Defaults to `true`\n * This prop has no effect if `disabled` is set to true.\n */\n canAddElements?: boolean;\n}\n\n/**\n * @group Entity properties\n */\nexport interface MapUIConfig extends BaseUIConfig {\n expanded?: boolean;\n minimalistView?: boolean;\n spreadChildren?: boolean;\n}\n\nexport interface MapProperty extends BaseProperty {\n ui?: MapUIConfig;\n type: \"map\";\n /**\n * Optional database column type. Defaults to `jsonb`.\n */\n columnType?: \"json\" | \"jsonb\";\n /**\n * Record of properties included in this map.\n */\n properties?: Properties;\n /**\n * Order in which the properties are displayed.\n * If you are specifying your collection as code, the order is the same as the\n * one you define in `properties`, and you don't need to specify this prop.\n */\n propertiesOrder?: string[];\n /**\n * Rules for validating this property.\n * NOTE: If you don't set `required` in the map property, an empty object\n * will be considered valid, even if you set `required` in the properties.\n */\n validation?: PropertyValidationSchema;\n /**\n * Properties that are displayed when rendered as a preview\n */\n previewProperties?: string[];\n /**\n * Render this map as a key-value table that allows to use\n * arbitrary keys. You don't need to define the properties in this case.\n */\n keyValue?: boolean;\n}\n\n/**\n * @group Entity properties\n */\nexport type PropertyBuilderProps<M extends Record<string, unknown> = Record<string, unknown>> = {\n values: Partial<M>;\n previousValues?: Partial<M>;\n propertyValue?: unknown;\n index?: number;\n path: string;\n entityId?: string | number;\n authController: AuthController;\n};\n\n/**\n * @group Entity properties\n */\nexport interface PropertyDisabledConfig {\n /**\n * Enable this flag if you would like to clear the value of the field\n * when the corresponding property gets disabled.\n *\n * This is useful for keeping data consistency when you have conditional\n * properties.\n */\n clearOnDisabled?: boolean;\n\n /**\n * Explanation of why this property is disabled (e.g. a different field\n * needs to be enabled)\n */\n disabledMessage?: string;\n\n /**\n * Set this flag to true if you want to hide this field when disabled\n */\n hidden?: boolean;\n}\n\n/**\n * We use this type to define mapping between string or number values in\n * the data source to a label (such in a select dropdown).\n * The key in this Record is the value saved in the driver, and the value in\n * this record is the label displayed in the UI.\n * You can add additional customization by assigning a {@link EnumValueConfig} for the\n * label instead of a simple string (for enabling or disabling options and\n * choosing colors).\n * If you need to ensure the order of the elements use an array of {@link EnumValueConfig}\n * @group Entity properties\n */\nexport type EnumValues = EnumValueConfig[] | Record<string | number, string | EnumValueConfig>;\n\n/**\n * Configuration for a particular entry in an `EnumValues`\n * @group Entity properties\n */\nexport type EnumValueConfig = {\n /**\n * Value stored in the data source.\n */\n id: string | number;\n /**\n * Displayed label\n */\n label: string;\n /**\n * This value will not be selectable\n */\n disabled?: boolean;\n /**\n * You can pick from a list of predefined color combinations or define\n * your own {@link ColorScheme}\n */\n color?: ColorKey | ColorScheme;\n}\n\n/**\n * Rules to validate any property. Some properties have specific rules\n * additionally to these.\n * @group Entity properties\n */\nexport interface PropertyValidationSchema {\n /**\n * Is this field required\n */\n required?: boolean;\n\n /**\n * Customize the required message when the property is not set\n */\n requiredMessage?: string;\n\n /**\n * If the unique flag is set to `true`, you can only have one entity in the\n * collection with this value.\n */\n unique?: boolean;\n\n /**\n * If the uniqueInArray flag is set to `true`, you can only have this value\n * once per entry in the parent `ArrayProperty`. It has no effect if this\n * property is not a child of an `ArrayProperty`. It works on direct\n * children of an `ArrayProperty` or first level children of `MapProperty`\n */\n uniqueInArray?: boolean;\n}\n\n/**\n * Validation rules for numbers\n * @group Entity properties\n */\nexport interface NumberPropertyValidationSchema extends PropertyValidationSchema {\n min?: number;\n max?: number;\n lessThan?: number;\n moreThan?: number;\n positive?: boolean;\n negative?: boolean;\n integer?: boolean;\n}\n\n/**\n * Validation rules for strings\n * @group Entity properties\n */\nexport interface StringPropertyValidationSchema extends PropertyValidationSchema {\n length?: number;\n min?: number;\n max?: number;\n matches?: string | RegExp;\n /**\n * Message displayed when the input does not satisfy the regex in `matches`\n */\n matchesMessage?: string;\n trim?: boolean;\n lowercase?: boolean;\n uppercase?: boolean;\n}\n\n/**\n * Validation rules for dates\n * @group Entity properties\n */\nexport interface DatePropertyValidationSchema extends PropertyValidationSchema {\n min?: Date;\n max?: Date;\n}\n\n/**\n * Validation rules for arrays\n * @group Entity properties\n */\nexport interface ArrayPropertyValidationSchema extends PropertyValidationSchema {\n min?: number;\n max?: number;\n}\n\n/**\n * Additional configuration related to Storage related fields\n * @group Entity properties\n */\nexport type StorageConfig = {\n /**\n * File MIME types that can be uploaded to this reference. Don't specify for\n * all.\n * Note that you can also use the asterisk notation, so `image/*`\n * accepts any image file, and so on.\n */\n acceptedFiles?: FileType[];\n\n /**\n * Advanced image resizing and cropping configuration.\n * Applied before upload to optimize storage and bandwidth.\n * Only applies to image MIME types: image/jpeg, image/png, image/webp\n */\n imageResize?: ImageResize;\n\n /**\n * Specific metadata set in your uploaded file.\n * For the default Firebase implementation, the values passed here are of type\n * `firebase.storage.UploadMetadata`\n */\n metadata?: Record<string, unknown>,\n\n /**\n * You can use this prop to customize the uploaded filename.\n * You can use a function as a callback or a string where you\n * specify some placeholders that get replaced with the corresponding values.\n * - `{file}` - Full file name\n * - `{file.name}` - Name of the file without extension\n * - `{file.ext}` - Extension of the file\n * - `{rand}` - Random value used to avoid name collisions\n * - `{entityId}` - ID of the entity\n * - `{propertyKey}` - ID of this property\n * - `{path}` - Path of this entity\n *\n * @param context\n */\n fileName?: string | ((context: UploadedFileContext) => string | Promise<string>);\n\n /**\n * Absolute path in your bucket.\n *\n * You can use a function as a callback or a string where you\n * specify some placeholders that get replaced with the corresponding values.\n * - `{file}` - Full file name\n * - `{file.name}` - Name of the file without extension\n * - `{file.ext}` - Extension of the file\n * - `{rand}` - Random value used to avoid name collisions\n * - `{entityId}` - ID of the entity\n * - `{propertyKey}` - ID of this property\n * - `{path}` - Path of this entity\n */\n storagePath: string | ((context: UploadedFileContext) => string);\n\n /**\n * When set to true, this flag indicates that the bucket name will be\n * included in the saved storage path.\n *\n * E.g. `s3://my-bucket/path/to/file.png` instead of just `path/to/file.png`\n *\n * Defaults to false.\n */\n includeBucketUrl?: boolean;\n\n /**\n * When set to true, this flag indicates that the download URL of the file\n * will be saved in the driver, instead of the storage path.\n *\n * Note that the generated URL may use a token that, if disabled, may\n * make the URL unusable and lose the original reference to Cloud Storage,\n * so it is not encouraged to use this flag.\n *\n * Defaults to false.\n */\n storeUrl?: boolean,\n\n /**\n * Define maximal file size in bytes\n */\n maxSize?: number,\n\n /**\n * Use this callback to process the file before uploading it to the storage.\n * If nothing is returned, the file is uploaded as it is.\n * @param file\n */\n processFile?: (file: File) => Promise<File> | undefined;\n\n /**\n * Postprocess the saved value (storage path or URL)\n * after it has been resolved.\n */\n postProcess?: (pathOrUrl: string) => Promise<string>;\n\n /**\n * You can use this prop in order to provide a custom preview URL.\n * Useful when the file's path is different from the original field value\n */\n previewUrl?: (fileName: string) => string;\n}\n\n/**\n * @group Entity properties\n */\nexport interface UploadedFileContext {\n /**\n * Uploaded file\n */\n file: File;\n\n /**\n * Property field name\n */\n propertyKey: string;\n\n /**\n * Property related to this upload\n */\n property: StringProperty | ArrayProperty;\n\n /**\n * Entity ID\n */\n entityId?: string | number;\n\n /**\n * Entity path. E.g. `products/PID/locales`\n */\n path?: string;\n\n /**\n * Values of the current entity\n */\n values: EntityValues<any>;\n\n /**\n * Storage meta specified by the developer\n */\n storage: StorageConfig;\n}\n\n/**\n * Used for previewing urls if the download file is known\n * @group Entity properties\n */\nexport type PreviewType = \"image\" | \"video\" | \"audio\" | \"file\";\n\n/**\n * MIME types for storage fields\n * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types\n * @group Entity properties\n */\nexport type FileType =\n | \"image/*\"\n | \"video/*\"\n | \"audio/*\"\n | \"application/*\"\n | \"text/*\"\n | \"font/*\"\n | string;\n\nexport interface ImageResize {\n /**\n * Maximum width in pixels. Image will be scaled down proportionally if wider.\n */\n maxWidth?: number;\n\n /**\n * Maximum height in pixels. Image will be scaled down proportionally if taller.\n */\n maxHeight?: number;\n\n /**\n * Resize mode determines how the image fits within maxWidth/maxHeight bounds.\n * - `contain`: Scale down to fit within bounds, preserving aspect ratio (default)\n * - `cover`: Scale to fill bounds, preserving aspect ratio (may crop)\n */\n mode?: \"contain\" | \"cover\";\n\n /**\n * Output format for the resized image.\n * - `original`: Keep the original format (default)\n * - `jpeg`: Convert to JPEG\n * - `png`: Convert to PNG\n * - `webp`: Convert to WebP\n */\n format?: \"original\" | \"jpeg\" | \"png\" | \"webp\";\n\n /**\n * Quality for lossy formats (JPEG, WebP). Number between 0 and 100.\n * Higher is better quality but larger file size. Defaults to 80.\n */\n quality?: number;\n}\n\n/**\n * A JSON Logic rule that gets evaluated at runtime.\n * @see https://jsonlogic.com/\n *\n * Common operators:\n * - Comparison: ==, !=, ===, !==, >, <, >=, <=\n * - Logic: and, or, !, !!\n * - Data access: var, missing, missing_some\n * - Array: in, map, filter, reduce, all, some, none, merge\n * - String: substr, cat\n * - Numeric: +, -, *, /, %, min, max\n *\n * Custom operators:\n * - hasRole(roleId) - check if user has role by ID\n * - hasAnyRole([roleIds]) - check if user has any of the roles\n * - isToday(timestamp) - check if timestamp is today\n * - isPast(timestamp) - check if timestamp is in the past\n * - isFuture(timestamp) - check if timestamp is in the future\n *\n * @group Entity properties\n */\nexport type JsonLogicRule = Record<string, any>;\n\n/**\n * Conditions for individual enum values within a property.\n * @group Entity properties\n */\nexport interface EnumValueConditions {\n /**\n * Disable this enum option when condition is true.\n * The option appears grayed out and cannot be selected.\n */\n disabled?: JsonLogicRule;\n\n /**\n * Message explaining why this option is disabled.\n */\n disabledMessage?: string;\n\n /**\n * Completely hide this enum option when condition is true.\n * The option is removed from the dropdown/list.\n */\n hidden?: JsonLogicRule;\n}\n\n/**\n * Declarative conditions for dynamic property behavior.\n * All conditions are JSON Logic rules evaluated against ConditionContext.\n *\n * An alternative to PropertyBuilder functions that can be:\n * - Stored in the database as JSON\n * - Edited via the collection editor UI\n * - Evaluated at runtime like property builders\n *\n * @see https://jsonlogic.com/ for JSON Logic syntax\n * @group Entity properties\n */\nexport interface PropertyConditions {\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIELD STATE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Disable the field when this condition evaluates to true.\n * The field becomes non-editable but still visible (unless also hidden).\n *\n * @example Disable when another field has a specific value\n * \\`\\`\\`json\n * { \"==\": [{ \"var\": \"values.status\" }, \"archived\"] }\n * \\`\\`\\`\n */\n disabled?: JsonLogicRule;\n\n /**\n * Message to display when the field is disabled by a condition.\n */\n disabledMessage?: string;\n\n /**\n * Clear the field's value when it becomes disabled.\n * @default false\n */\n clearOnDisabled?: boolean;\n\n /**\n * Hide the field completely when this condition evaluates to true.\n * The field is removed from the form (not just visually hidden).\n */\n hidden?: JsonLogicRule;\n\n /**\n * Make the field read-only when this condition evaluates to true.\n * Renders as a preview instead of an input.\n */\n readOnly?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALIDATION CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Make the field required when this condition evaluates to true.\n * Overrides the static `validation.required` setting.\n */\n required?: JsonLogicRule;\n\n /**\n * Custom message when conditional required validation fails.\n */\n requiredMessage?: string;\n\n /**\n * Dynamic minimum value for number/string length.\n * Should evaluate to a number.\n */\n min?: JsonLogicRule;\n\n /**\n * Dynamic maximum value for number/string length.\n * Should evaluate to a number.\n */\n max?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALUE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Dynamic default value for new entities.\n * Should evaluate to a value of the appropriate type for the field.\n * Only applied when entityId is empty (new entity).\n */\n defaultValue?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // ENUM CONDITIONS (for string/number properties with enumValues)\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Conditions for individual enum values.\n * Keys are the enum value IDs, values are condition configs.\n *\n * @example Disable certain enum options based on user role\n * \\`\\`\\`json\n * {\n * \"admin\": {\n * \"disabled\": { \"!\": { \"hasRole\": \"admin\" } },\n * \"disabledMessage\": \"Admin option requires admin role\"\n * }\n * }\n * \\`\\`\\`\n */\n enumConditions?: Record<string | number, EnumValueConditions>;\n\n /**\n * Filter which enum values are available.\n * Should evaluate to an array of allowed enum value IDs.\n */\n allowedEnumValues?: JsonLogicRule;\n\n /**\n * Exclude specific enum values.\n * Should evaluate to an array of enum value IDs to exclude.\n */\n excludedEnumValues?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFERENCE CONDITIONS (for reference properties)\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Dynamic path for reference properties.\n * Should evaluate to a collection path string.\n */\n referencePath?: JsonLogicRule;\n\n /**\n * Dynamic filter for reference selection.\n * Should evaluate to a FilterValues object.\n */\n referenceFilter?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // ARRAY CONDITIONS (for array properties)\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Can elements be added to the array?\n */\n canAddElements?: JsonLogicRule;\n\n /**\n * Can elements be reordered in the array?\n */\n sortable?: JsonLogicRule;\n\n // ═══════════════════════════════════════════════════════════════════════\n // STORAGE CONDITIONS (for file upload properties)\n // ═══════════════════════════════════════════════════════════════════════\n\n /**\n * Dynamic accepted file types.\n * Should evaluate to an array of MIME types.\n */\n acceptedFiles?: JsonLogicRule;\n\n /**\n * Dynamic maximum file size in bytes.\n * Should evaluate to a number.\n */\n maxFileSize?: JsonLogicRule;\n}\n\n/**\n * Context available during JSON Logic condition evaluation.\n * Mirrors PropertyBuilderProps but adapted for JSON serialization.\n * @group Entity properties\n */\nexport interface ConditionContext {\n /**\n * Current form/entity values.\n * Date values are converted to Unix timestamps (milliseconds).\n */\n values: Record<string, unknown>;\n\n /**\n * Previous values before the current edit session.\n */\n previousValues: Record<string, unknown>;\n\n /**\n * Current value of this property specifically.\n */\n propertyValue: unknown;\n\n /**\n * Collection path (e.g., \"products\", \"users/uid123/orders\")\n */\n path: string;\n\n /**\n * Entity ID. Undefined for new entities.\n */\n entityId?: string;\n\n /**\n * Whether this is a new entity being created.\n */\n isNew: boolean;\n\n /**\n * Index of this property (only for array items).\n */\n index?: number;\n\n /**\n * Current authenticated user information.\n */\n user: {\n uid: string;\n email: string | null;\n displayName: string | null;\n photoURL: string | null;\n /** Role IDs the user has (extracted from Role[].id) */\n roles: string[];\n };\n\n /**\n * Current timestamp as Unix milliseconds.\n */\n now: number;\n}\n","import React, { Dispatch, SetStateAction } from \"react\";\nimport type { Entity, EntityStatus, EntityValues } from \"./entities\";\nimport type { EntityCallbacks } from \"./entity_callbacks\";\n\nimport type { EnumValues, Properties } from \"./properties\";\nimport type { ExportConfig } from \"./export_import\";\nimport type { EntityOverrides } from \"./entity_overrides\";\nimport type { User } from \"../users\";\nimport type { RebaseContext } from \"../rebase_context\";\nimport type { Relation } from \"./relations\";\nimport type { EntityCustomView, FormViewConfig } from \"./entity_views\";\nimport type { EntityAction } from \"./entity_actions\";\nimport type { ComponentRef } from \"./component_ref\";\nimport type { CollectionComponentOverrideMap } from \"./component_overrides\";\n\n/**\n * Base interface containing all driver-agnostic collection properties.\n * Use {@link PostgresCollection} or {@link FirebaseCollection} for\n * driver-specific type safety, or {@link EntityCollection} when you\n * need to handle any collection regardless of backend.\n *\n * @group Models\n */\nexport interface BaseEntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n\n /**\n * You can set an alias that will be used internally instead of the collection name.\n * The `slug` value will be used to determine the URL of the collection.\n * Note that you can use this value in reference properties too.\n */\n slug: string;\n\n /**\n * Name of the collection, typically plural.\n * E.g. `Products`, `Blog`\n */\n name: string;\n\n /**\n * Singular name of an entry in this collection\n * E.g. `Product`, `Blog entry`\n */\n singularName?: string;\n\n /**\n * Optional description of this view. You can use Markdown.\n */\n description?: string;\n\n /**\n * Child collections nested under entities of this collection.\n * Populated automatically during normalization from driver-specific fields\n * (e.g. Firebase `subcollections`, Postgres `relations` with many-cardinality).\n *\n * Custom drivers can set this directly to expose child collections to the UI.\n */\n childCollections?: () => EntityCollection<Record<string, unknown>>[];\n\n\n /**\n * Which driver handles this collection.\n * Use this to route collections to different backends:\n * - `\"postgres\"` - Route to PostgreSQL backend\n * - `\"firestore\"` - Route to Firestore (client-side)\n * - `\"mongodb\"` - Route to MongoDB backend\n * - Custom IDs for your own driver implementations\n *\n * If not specified, the default driver `\"(default)\"` is used.\n *\n * @example\n * // Simple - no driver needed for default\n * { slug: \"products\" }\n *\n * // Firestore collection (client-side real-time)\n * { slug: \"analytics\", driver: \"firestore\" }\n *\n * // Multiple databases within a driver\n * { slug: \"orders\", driver: \"postgres\", databaseId: \"orders_db\" }\n */\n driver?: string;\n\n /**\n * Which database within the driver.\n * - For Firestore: The Firestore database ID (e.g., for multi-database projects)\n * - For PostgreSQL: Schema or database name\n * - For MongoDB: Database name\n *\n * If not specified, the default database of the driver is used.\n */\n databaseId?: string;\n\n /**\n * Set of properties that compose an entity\n */\n properties: Properties;\n\n /**\n * Icon for the navigation sidebar or cards.\n */\n icon?: string | React.ReactNode;\n\n /**\n * Navigation group for this collection.\n * Collections sharing the same group name will be visually grouped\n * together in the drawer and home page. If not set, the collection\n * falls into the default \"Views\" group.\n */\n group?: string;\n\n /**\n * Array of entity views that this collection has.\n * Can be an array of `EntityCustomView` or a string representing the key of a global `EntityCustomView`.\n */\n entityViews?: (string | EntityCustomView<Record<string, unknown>>)[];\n\n /**\n * Default preview properties displayed when this collection is referenced to.\n */\n previewProperties?: string[];\n\n /**\n * Properties to display as columns in the list view.\n * If not specified, the list view uses a smart default (Title, Status, Date).\n */\n listProperties?: string[];\n\n /**\n * Title property of the entity. This is the property that will be used\n * as the title in entity related views and references.\n * If not specified, the first property simple text property will be used.\n */\n readonly titleProperty?: Extract<keyof M, string> | (string & {});\n\n /**\n * When editing an entity, you can choose to open the entity in a side dialog\n * or in a full screen dialog. Defaults to `full_screen`.\n */\n openEntityMode?: \"side_panel\" | \"full_screen\" | \"split\" | \"dialog\";\n\n /**\n * Controls what happens when a user clicks on an entity in the collection view.\n * - `\"edit\"` (default): Opens the entity in the edit form.\n * - `\"view\"`: Opens a read-only detail view with an \"Edit\" button.\n */\n defaultEntityAction?: \"view\" | \"edit\";\n\n /**\n * Replace the default entity form with a custom component.\n * The Builder receives the same props as entity view tabs\n * (entity, formContext, collection, etc.) and has full control over the UI.\n *\n * Works in both edit mode and read-only mode (when `defaultEntityAction`\n * is `\"view\"`). In read-only mode, `formContext.readOnly` will be `true`.\n */\n formView?: FormViewConfig;\n\n /**\n * Prevent default actions from being displayed or executed on this collection.\n */\n disableDefaultActions?: (\"edit\" | \"copy\" | \"delete\")[];\n\n /**\n * Mark this collection as an authentication collection.\n * When true, this collection is used for user management, login, password hashing, and invitation flows.\n */\n auth?: boolean | AuthCollectionConfig;\n\n\n /**\n * Order in which the properties are displayed.\n * If you are specifying your collection as code, the order is the same as the\n * one you define in `properties`. Additional columns are added at the\n * end of the list, if the order is not specified.\n * You can use this prop to hide some properties from the table view.\n * Note that if you set this prop, other ways to hide fields, like\n * `hidden` in the property definition, will be ignored.\n * `propertiesOrder` has precedence over `hidden`.\n * - For properties use the property key.\n * - For additional fields use the field key.\n * - If you have subcollections, you get a column for each subcollection,\n * with the path (or alias) as the subcollection, prefixed with\n * `subcollection:`. e.g. `subcollection:orders`.\n * You can use this prop to hide some properties from the table view.\n * Note that if you set this prop, other ways to hide fields, like\n * `hidden` in the property definition,will be ignored.\n * `propertiesOrder` has precedence over `hidden`.\n */\n propertiesOrder?: (Extract<keyof M, string> | (string & {}) | string | `subcollection:${string}`)[];\n\n /**\n * If enabled, content is loaded in batches. If `false` all entities in the\n * collection are loaded. This means that when reaching the end of the\n * collection, the CMS will load more entities.\n * You can specify a number to specify the pagination size (50 by default)\n * Defaults to `true`\n */\n pagination?: boolean | number;\n\n\n selectionEnabled?: boolean;\n\n /**\n * This interface defines all the callbacks that can be used when an entity\n * is being created, updated or deleted.\n * Useful for adding your own logic or blocking the execution of the operation.\n */\n readonly callbacks?: EntityCallbacks<M, USER>;\n\n /**\n * Pass your own selection controller if you want to control selected\n * entities externally.\n * @see useSelectionController\n */\n selectionController?: SelectionController<M>;\n\n /**\n * Force a filter in this view. If applied, the rest of the filters will\n * be disabled. Filters applied with this prop cannot be changed.\n * e.g. `fixedFilter: { age: [\">\", 18] }`\n * e.g. `fixedFilter: { related_user: [\"==\", new EntityReference(\"sdc43dsw2\", \"users\")] }`\n */\n readonly fixedFilter?: FilterValues<Extract<keyof M, string> | (string & {})>;\n\n /**\n * Initial filters applied to the collection this collection is related to.\n * Defaults to none. Filters applied with this prop can be changed.\n * e.g. `defaultFilter: { age: [\">\", 18] }`\n * e.g. `defaultFilter: { related_user: [\"==\", new EntityReference(\"sdc43dsw2\", \"users\")] }`\n */\n readonly defaultFilter?: FilterValues<Extract<keyof M, string> | (string & {})>; // setting FilterValues<M> can break defining collections by code\n\n /**\n * Pre-defined filter presets that appear as quick-access options in the\n * collection toolbar. Each preset applies a set of filters (and\n * optionally a sort order) with a single click.\n *\n * ```ts\n * filterPresets: [\n * {\n * label: \"Shipped this month\",\n * filterValues: {\n * status: [\"==\", \"shipped\"],\n * order_date: [\">=\", new Date(Date.now() - 30 * 86400000)]\n * }\n * }\n * ]\n * ```\n */\n readonly filterPresets?: FilterPreset<Extract<keyof M, string> | (string & {})>[];\n\n /**\n * Default sort applied to this collection.\n * When setting this prop, entities will have a default order\n * applied in the collection.\n * e.g. `sort: [\"order\", \"asc\"]`\n */\n readonly sort?: [Extract<keyof M, string> | (string & {}), \"asc\" | \"desc\"];\n\n /**\n * You can add additional fields to the collection view by implementing\n * an additional field delegate.\n */\n readonly additionalFields?: AdditionalFieldDelegate<M, USER>[];\n\n /**\n * Default size of the rendered collection\n */\n defaultSize?: CollectionSize;\n\n /**\n * Can the elements in this collection be edited inline in the collection\n * view. If this flag is set to false but `permissions.edit` is `true`, entities\n * can still be edited in the side panel\n */\n inlineEditing?: boolean;\n\n /**\n * Should this collection be hidden from the main navigation panel, if\n * it is at the root level, or in the entity side panel if it's a\n * subcollection.\n * It will still be accessible if you reach the specified path.\n * You can also use this collection as a reference target.\n */\n hideFromNavigation?: boolean;\n\n /**\n * If you want to open custom views or subcollections by default when opening the edit\n * view of an entity, you can specify the path to the view here.\n * The path is relative to the current collection. For example if you have a collection\n * that has a custom view as well as a subcollection that refers to another entity, you can\n * either specify the path to the custom view or the path to the subcollection.\n */\n defaultSelectedView?: string | DefaultSelectedViewBuilder;\n\n /**\n * Should the ID of this collection be hidden from the form view.\n */\n hideIdFromForm?: boolean;\n\n /**\n * Should the ID of this collection be hidden from the grid view.\n */\n hideIdFromCollection?: boolean;\n\n /**\n * If set to true, the form will be auto-saved when the user changes\n * the value of a field.\n * Defaults to false.\n * When a new entity is created, this property can be updated to generated a new ID\n */\n formAutoSave?: boolean;\n\n /**\n *\n */\n exportable?: boolean | ExportConfig<USER>;\n\n /**\n * User id of the owner of this collection. This is used only by plugins, or if you\n * are writing custom code\n */\n ownerId?: string;\n\n /**\n * Overrides for the entity view, like the data source or the storage source.\n */\n overrides?: EntityOverrides;\n\n /**\n * Width of the side dialog (in pixels) when opening an entity in this collection.\n */\n sideDialogWidth?: number | string;\n\n /**\n * If set to true, the default values of the properties will be applied\n * to the entity every time the entity is updated (not only when created).\n * Defaults to false.\n */\n alwaysApplyDefaultValues?: boolean;\n\n /**\n * If set to true, a tab including the JSON representation of the entity will be included.\n */\n includeJsonView?: boolean;\n\n /**\n * If set to true, changes to the entity will be saved in a subcollection.\n * This prop has no effect if the history plugin is not enabled\n */\n history?: boolean;\n\n /**\n * Should local changes be backed up in local storage, to prevent data loss on\n * accidental navigations.\n * - `manual_apply`: When the user navigates back to an entity with local changes,\n * they will be prompted to restore the changes.\n * - `auto_apply`: When the user navigates back to an entity with local changes,\n * the changes will be automatically applied.\n * - `false`: Local changes will not be backed up.\n * Defaults to `manual_apply`.\n */\n localChangesBackup?: \"manual_apply\" | \"auto_apply\" | false;\n\n /**\n * Default view mode for displaying this collection.\n * - \"table\": Display entities in a table with inline editing (default)\n * - \"cards\": Display entities as a grid of cards with thumbnails\n * - \"kanban\": Display entities in a Kanban board grouped by a property\n * Defaults to \"table\".\n */\n defaultViewMode?: ViewMode;\n\n /**\n * Which view modes are available for this collection.\n * Possible values: \"table\", \"cards\", \"kanban\".\n * Defaults to all three: [\"table\", \"cards\", \"kanban\"].\n * Note: \"kanban\" will only be available if the collection has at least\n * one string property with enumValues defined, regardless of this setting.\n */\n enabledViews?: ViewMode[];\n\n /**\n * Configuration for Kanban board view mode.\n * When set, the Kanban view mode becomes available.\n */\n kanban?: KanbanConfig<M>;\n\n /**\n * Property key to use for ordering items.\n * Must reference a string/text property. When items are reordered,\n * this property will be updated with lexicographic sort keys\n * (e.g. \"a0\", \"a1\", \"a0V\") using string-based fractional indexing.\n * Used by Kanban view for ordering within columns\n * and can be used for general ordering purposes.\n */\n readonly orderProperty?: Extract<keyof M, string> | (string & {});\n\n /**\n * Actions that can be performed on the entities in this collection.\n */\n entityActions?: EntityAction<M, USER>[];\n\n /**\n * Builder for the collection actions rendered in the toolbar\n */\n Actions?: ComponentRef<CollectionActionsProps>[];\n\n /**\n * The database table name for this collection.\n * Automatically set for PostgreSQL collections.\n * For non-SQL backends, this may be undefined.\n */\n table?: string;\n\n /**\n * Relations defined for this collection.\n * Populated at normalization time from inline relation properties\n * or explicit relation definitions.\n */\n relations?: Relation[];\n\n /**\n * Security rules for this collection (Row Level Security).\n * When defined, the backend enforces access control policies.\n */\n securityRules?: SecurityRule[];\n\n /**\n * Collection-scoped component overrides. These take precedence over\n * global overrides set on `<Rebase>`, but only within this collection's\n * views (entity form, detail view, table, empty state, etc.).\n *\n * Only collection-scoped components (like `Entity.Form`, `Collection.EmptyState`,\n * `Collection.Card`, etc.) can be overridden here. App-level components\n * (like `Shell.AppBar`, `HomePage`) can only be overridden at the `<Rebase>` level.\n *\n * @example\n * ```tsx\n * const productsCollection: PostgresCollection = {\n * name: \"Products\",\n * slug: \"products\",\n * table: \"products\",\n * components: {\n * \"Entity.Form\": { Component: ProductCustomForm },\n * \"Collection.Card\": { Component: ProductCard },\n * },\n * properties: { ... }\n * };\n * ```\n */\n components?: CollectionComponentOverrideMap;\n}\n\n// ── Driver-specific collection types ──────────────────────────────────\n\n/**\n * A collection backed by PostgreSQL (or any SQL database).\n * Adds support for SQL-style relations (JOINs) and Row Level Security.\n *\n * Use this type instead of {@link EntityCollection} when you want\n * compile-time safety that only SQL-relevant fields appear.\n *\n * @group Models\n */\nexport interface PostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>\n extends BaseEntityCollection<M, USER> {\n properties: Properties;\n\n /**\n * The driver for this collection. For Postgres collections this\n * can be omitted (Postgres is the default) or set to `\"postgres\"`.\n */\n driver?: \"postgres\" | undefined;\n\n /**\n * The PostgreSQL table name for this collection.\n */\n table: string;\n\n /**\n * The PostgreSQL schema name for this table.\n * E.g. \"public\", \"rebase\", \"auth\".\n * If not specified, \"public\" is used (or the default search path).\n */\n schema?: string;\n\n /**\n * For SQL databases, you can define the relations between collections here.\n * Relations describe JOINs, foreign keys, and junction tables.\n */\n relations?: Relation[];\n\n /**\n * Security rules for this collection (Supabase-style Row Level Security).\n * When defined, the schema generator will enable RLS on the table and\n * create the corresponding PostgreSQL policies.\n *\n * Supports three levels of expressiveness:\n * 1. **Convenience shortcuts** — `ownerField`, `access`, `roles`\n * 2. **Raw SQL** — `using` and `withCheck` for full PostgreSQL power\n * 3. **Combined** — mix shortcuts with `roles` for common patterns\n *\n * The authenticated user context is available in raw SQL via:\n * - `auth.uid()` — the current user's ID\n * - `auth.roles()` — comma-separated app role IDs\n * - `auth.jwt()` — full JWT claims as JSONB\n */\n securityRules?: SecurityRule[];\n}\n\n/**\n * A collection backed by Firebase / Firestore.\n * Adds support for subcollections (nested document collections).\n *\n * Use this type instead of {@link EntityCollection} when you want\n * compile-time safety that only Firestore-relevant fields appear.\n *\n * @group Models\n */\nexport interface FirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>\n extends BaseEntityCollection<M, USER> {\n /**\n * The driver for this collection. Must be set to `\"firestore\"`.\n */\n driver: \"firestore\";\n\n /**\n * You can add subcollections to your entity in the same way you define the root\n * collections. The collections added here will be displayed when opening\n * the side dialog of an entity.\n */\n subcollections?: () => EntityCollection<Record<string, unknown>>[];\n}\n\n/**\n * A collection backed by MongoDB.\n *\n * Use this type instead of {@link EntityCollection} when you want\n * compile-time safety that only MongoDB-relevant fields appear.\n *\n * @group Models\n */\nexport interface MongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>\n extends BaseEntityCollection<M, USER> {\n\n /**\n * The driver for this collection. Must be set to `\"mongodb\"`.\n */\n driver: \"mongodb\";\n}\n\n/**\n * A collection backed by any data source.\n * This is a discriminated union — use {@link PostgresCollection},\n * {@link FirebaseCollection}, or {@link MongoDBCollection} for\n * driver-specific type safety.\n *\n * @group Models\n */\nexport type EntityCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =\n | PostgresCollection<M, USER>\n | FirebaseCollection<M, USER>\n | MongoDBCollection<M, USER>;\n\n// ── Capability intersection types ─────────────────────────────────────\n// Use these after a `getDataSourceCapabilities()` guard to safely access\n// driver-specific fields without coupling to a concrete driver type.\n\n/**\n * An EntityCollection that supports SQL-style relations (e.g. Postgres).\n * @deprecated Use `EntityCollection` directly — `table`, `relations`, and `securityRules` are now on `BaseEntityCollection`.\n */\nexport type CollectionWithRelations<M extends Record<string, unknown> = Record<string, unknown>> =\n EntityCollection<M> & { table?: string; relations?: Relation[]; securityRules?: SecurityRule[] };\n\n/** An EntityCollection that supports subcollections (e.g. Firestore). */\nexport type CollectionWithSubcollections<M extends Record<string, unknown> = Record<string, unknown>> =\n EntityCollection<M> & { subcollections?: () => EntityCollection<Record<string, unknown>>[] };\n\n\n// ── Type guards ───────────────────────────────────────────────────────\n\n/**\n * Type guard for PostgreSQL collections.\n * Returns true if the collection uses the Postgres driver (or the default driver).\n * @group Models\n */\nexport function isPostgresCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(\n collection: EntityCollection<M, USER>\n): collection is PostgresCollection<M, USER> {\n return !collection.driver || collection.driver === \"postgres\";\n}\n\n/**\n * Type guard for Firebase / Firestore collections.\n * @group Models\n */\nexport function isFirebaseCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(\n collection: EntityCollection<M, USER>\n): collection is FirebaseCollection<M, USER> {\n return collection.driver === \"firestore\";\n}\n\n/**\n * Type guard for MongoDB collections.\n * @group Models\n */\nexport function isMongoDBCollection<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User>(\n collection: EntityCollection<M, USER>\n): collection is MongoDBCollection<M, USER> {\n return collection.driver === \"mongodb\";\n}\n\n\n/**\n * Configuration for Kanban board view mode.\n * @group Collections\n */\nexport interface KanbanConfig<M extends Record<string, unknown> = Record<string, unknown>> {\n /**\n * Property key to use for Kanban board columns.\n * Must reference a string property with enumValues defined.\n * Entities will be grouped into columns based on this property's value.\n * The column order is determined by the order of enumValues in the property.\n */\n columnProperty: Extract<keyof M, string> | (string & {});\n}\n\n/**\n * View mode for displaying a collection.\n * - \"list\": Simple, clean list view — the classic CMS default\n * - \"table\": Table with inline editing\n * - \"cards\": Grid of visual cards with thumbnails\n * - \"kanban\": Board view grouped by a property\n * @group Collections\n */\nexport type ViewMode = \"list\" | \"table\" | \"cards\" | \"kanban\";\n\n/**\n * Parameter passed to the `Actions` prop in the collection configuration.\n * The component will receive this prop when it is rendered in the collection\n * toolbar.\n *\n * @group Models\n */\nexport interface CollectionActionsProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends EntityCollection<M> = EntityCollection<M>> {\n /**\n * Full collection path of this entity. This is the full path, like\n * `users/1234/addresses`\n */\n path: string;\n\n /**\n * Path of the last collection, like `addresses`\n */\n relativePath: string;\n\n /**\n * Array of the parent path segments like `['users']`\n */\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n\n /**\n * The collection configuration\n */\n collection: EC;\n\n /**\n * Use this controller to get the selected entities and to update the\n * selected entities state.\n */\n selectionController: SelectionController<M>;\n\n /**\n * Use this controller to get the table controller and to update the\n * table controller state.\n */\n tableController: EntityTableController<M>;\n\n /**\n * Context of the app status\n */\n context: RebaseContext<USER>;\n\n /**\n * Count of the entities in this collection.\n * undefined means the count is still loading.\n */\n collectionEntitiesCount?: number;\n\n /**\n * Programmatically open the new-document form for this collection,\n * optionally pre-populating it with initial field values.\n * The form opens in the same mode configured for the collection\n * (side panel, full screen, or split).\n *\n * This is the primary hook for workflows that need to create a document\n * from external data — e.g. fetching content from a URL, importing from\n * a third-party API, or duplicating from another system.\n *\n * @example\n * // Inside a custom CollectionAction component:\n * openNewDocument({ title: \"Fetched title\", body: \"...\" });\n */\n openNewDocument: (defaultValues?: Record<string, unknown>) => void;\n\n}\n\n/**\n * Use this controller to retrieve the selected entities or modify them in\n * an {@link EntityCollection}\n * @group Models\n */\nexport interface SelectionController<M extends Record<string, unknown> = Record<string, unknown>> {\n selectedEntities: Entity<M>[];\n setSelectedEntities(entities: Entity<M>[]): void;\n setSelectedEntities(action: (prev: Entity<M>[]) => Entity<M>[]): void;\n isEntitySelected(entity: Entity<M>): boolean;\n toggleEntitySelection(entity: Entity<M>, newSelectedState?: boolean): void;\n}\n\n/**\n * Filter conditions in a `Query.where()` clause are specified using the\n * strings `<`, `<=`, `==`, `>=`, `>`, `array-contains`, `in`, and `array-contains-any`.\n * @group Models\n */\nexport type WhereFilterOp =\n | \"<\"\n | \"<=\"\n | \"==\"\n | \"!=\"\n | \">=\"\n | \">\"\n | \"array-contains\"\n | \"in\"\n | \"not-in\"\n | \"array-contains-any\";\n\n/**\n * Used to define filters applied in collections\n *\n * e.g. `{ age: [\">=\", 18] }`\n *\n * @group Models\n */\nexport type FilterValues<Key extends string> =\n Partial<Record<Key, [WhereFilterOp, unknown] | [WhereFilterOp, unknown][]>>;\n\n/**\n * A pre-defined filter preset for quick access in the collection toolbar.\n * Users can select a preset to instantly apply a set of filters and\n * optionally a sort order.\n *\n * @group Models\n */\nexport interface FilterPreset<Key extends string = string> {\n /**\n * Display label shown in the preset menu.\n * If omitted, a summary is auto-generated from the filter keys.\n */\n label?: string;\n\n /**\n * The filter values to apply when this preset is selected.\n */\n filterValues: FilterValues<Key>;\n\n /**\n * Optional sort override to apply alongside the filter values.\n */\n sort?: [Key, \"asc\" | \"desc\"];\n}\n\n\n/**\n * Used to indicate valid filter combinations (e.g. created in Firestore)\n * If the user selects a specific filter/sort combination, the CMS checks if it's\n * valid, otherwise it reverts to the simpler valid case\n * @group Models\n */\nexport type FilterCombination<Key extends string> = Partial<Record<Key, \"asc\" | \"desc\">>;\n\n/**\n * Sizes in which a collection can be rendered\n * @group Models\n */\nexport type CollectionSize = \"xs\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport type AdditionalFieldDelegateProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {\n entity: Entity<M>,\n context: RebaseContext<USER>\n};\n\n/**\n * Use this interface for adding additional fields to entity collection views and forms.\n * @group Models\n */\nexport interface AdditionalFieldDelegate<M extends Record<string, unknown> = Record<string, unknown>,\n USER extends User = User> {\n\n /**\n * ID of this column. You can use this id in the `properties` field of the\n * collection in any order you want\n */\n key: string;\n\n /**\n * Header of this column\n */\n name: string;\n\n /**\n * Width of the generated column in pixels\n */\n width?: number;\n\n /**\n * Builder for the custom field\n */\n Builder?(props: { entity: Entity<M>, context: RebaseContext<USER> }): React.ReactNode;\n\n\n /**\n * If this column needs to update dynamically based on other properties,\n * you can define an array of keys as strings with the\n * `dependencies` prop.\n * e.g. [\"name\", \"surname\"]\n * This is a performance optimization, if you don't define dependencies\n * it will be updated in every render.\n */\n dependencies?: NoInfer<Extract<keyof M, string>> | NoInfer<Extract<keyof M, string>>[] | (string & {}) | (string & {})[];\n\n /**\n * Use this prop to define the value of the column as a string or number.\n * This is the value that will be used for exporting the collection.\n * If `Builder` is defined, this prop will be ignored in the collection\n * view.\n * @param entity\n */\n value?(props: {\n entity: Entity<M>,\n context: RebaseContext\n }): string | number | Promise<string | number> | undefined;\n}\n\n\nexport type InferCollectionType<S extends EntityCollection> = S extends EntityCollection<infer M> ? M : never;\n\n/**\n * Used in the {@link EntityCollection#defaultSelectedView} to define the default\n * @group Models\n */\nexport type DefaultSelectedViewBuilder = (params: DefaultSelectedViewParams) => string | undefined;\n\n/**\n * Used in the {@link EntityCollection#defaultSelectedView} to define the default\n * @group Models\n */\nexport type DefaultSelectedViewParams = {\n status?: EntityStatus;\n entityId?: string | number;\n};\n/**\n * You can use this controller to control the table view of a collection.\n */\nexport type EntityTableController<M extends Record<string, unknown> = Record<string, unknown>> = {\n data: Entity<M>[];\n dataLoading: boolean;\n noMoreToLoad: boolean;\n dataLoadingError?: Error;\n filterValues?: FilterValues<Extract<keyof M, string> | (string & {})>;\n setFilterValues?: (filterValues: FilterValues<Extract<keyof M, string> | (string & {})>) => void;\n sortBy?: [Extract<keyof M, string> | (string & {}), \"asc\" | \"desc\"];\n setSortBy?: (sortBy?: [Extract<keyof M, string> | (string & {}), \"asc\" | \"desc\"]) => void;\n searchString?: string;\n setSearchString?: (searchString?: string) => void;\n clearFilter?: () => void;\n itemCount?: number;\n setItemCount?: (itemCount: number) => void;\n initialScroll?: number;\n onScroll?: (props: {\n scrollDirection: \"forward\" | \"backward\",\n scrollOffset: number,\n scrollUpdateWasRequested: boolean\n }) => void;\n paginationEnabled?: boolean;\n pageSize?: number;\n checkFilterCombination?: (filterValues: FilterValues<string>,\n sortBy?: [string, \"asc\" | \"desc\"]) => boolean;\n popupCell?: SelectedCellProps<M>;\n setPopupCell?: (popupCell?: SelectedCellProps<M>) => void;\n\n onAddColumn?: (column: string) => void;\n}\n\nexport type SelectedCellProps<M extends Record<string, unknown> = Record<string, unknown>> = {\n propertyKey: Extract<keyof M, string> | (string & {});\n cellRect: DOMRect;\n width: number;\n height: number;\n entityPath: string;\n entityId: string | number;\n};\n\n/**\n * SQL operation that a policy applies to.\n * @group Models\n */\nexport type SecurityOperation = \"select\" | \"insert\" | \"update\" | \"delete\" | \"all\";\n\n/**\n * Flexible Row Level Security rule for a collection.\n *\n * Inspired by Supabase's approach to PostgreSQL RLS. Rules can range from\n * simple convenience shortcuts to fully custom SQL expressions, giving you the\n * full power of PostgreSQL Row Level Security.\n *\n * The authenticated user's identity is available in raw SQL via:\n * - `auth.uid()` — the user's ID\n * - `auth.roles()` — comma-separated app role IDs\n * - `auth.jwt()` — full JWT claims as JSONB\n *\n * These are set automatically per-transaction by the backend.\n *\n * **How rules combine:** PostgreSQL evaluates all matching policies for an\n * operation. Permissive rules are OR'd together (any one passing is enough).\n * Restrictive rules are AND'd (all must pass). This mirrors Supabase behavior.\n *\n * **Mutual exclusivity:** `ownerField`, `access`, and raw SQL (`using`/`withCheck`)\n * cannot be combined. The type system enforces this — attempting to set\n * conflicting fields will produce a compile-time error.\n *\n * @group Models\n */\nexport type SecurityRule = OwnerSecurityRule | PublicSecurityRule | RawSQLSecurityRule | RolesOnlySecurityRule;\n\n/**\n * Shared fields for all SecurityRule variants.\n * @group Models\n */\nexport interface SecurityRuleBase {\n /**\n * Optional human-readable name for the policy.\n * If not provided, one will be auto-generated from the table name and operation.\n * Must be unique per table.\n *\n * When using `operations` (array), each generated policy will have the\n * operation name appended, e.g. `\"owner_access_select\"`, `\"owner_access_update\"`.\n */\n name?: string;\n\n /**\n * Which SQL operation this policy applies to.\n * Use this when the policy targets a single operation or all operations.\n *\n * For multiple specific operations, use `operations` (array) instead.\n * If neither is specified, defaults to `\"all\"`.\n *\n * @default \"all\"\n */\n operation?: SecurityOperation;\n\n /**\n * Array of SQL operations this policy applies to.\n * The compiler will generate one PostgreSQL policy per operation, sharing\n * the same configuration.\n *\n * This reduces boilerplate when the same rule applies to multiple (but not all)\n * operations.\n *\n * Takes precedence over `operation` (singular) if both are specified.\n *\n * @example\n * // Same rule for select and update\n * { operations: [\"select\", \"update\"], ownerField: \"user_id\" }\n *\n * @example\n * // Equivalent to operation: \"all\"\n * { operations: [\"all\"], ownerField: \"user_id\" }\n */\n operations?: SecurityOperation[];\n\n /**\n * Whether this policy is `\"permissive\"` (default) or `\"restrictive\"`.\n *\n * - **permissive**: Multiple permissive policies for the same operation are\n * OR'd together — if *any* passes, access is granted.\n * - **restrictive**: Restrictive policies are AND'd with all permissive\n * policies — they act as additional gates that *must* also pass.\n *\n * This is the same model as PostgreSQL / Supabase.\n *\n * @default \"permissive\"\n */\n mode?: \"permissive\" | \"restrictive\";\n\n /**\n * **Shortcut.** Restrict this rule to users that have one of these\n * application-level roles.\n *\n * **Important:** These are NOT native PostgreSQL database roles. They are\n * application roles managed by Rebase, stored in the `rebase.user_roles`\n * table, and injected into each transaction via `auth.roles()`.\n *\n * Generates a condition like:\n * `auth.roles() ~ '<role1>|<role2>'`\n *\n * Can be combined with `ownerField`, `access`, or raw `using`/`withCheck`.\n * When combined, the role check is AND'd with the other condition.\n *\n * @example\n * // Only admins can delete\n * { operation: \"delete\", roles: [\"admin\"] }\n *\n * @example\n * // Admins have unfiltered read access to all rows\n * { operation: \"select\", roles: [\"admin\"], using: \"true\" }\n */\n roles?: string[];\n\n // ── Advanced: native PostgreSQL role targeting ───────────────────────\n\n /**\n * **Advanced.** Native PostgreSQL database roles the policy applies to.\n *\n * By default, all generated policies target the `public` role (i.e.\n * every database connection). This is correct for most setups where\n * a single database role is used for all connections.\n *\n * **Important:** These are NOT the same as the application-level `roles`\n * (admin, editor, viewer, etc.) — those are enforced in the USING/WITH\n * CHECK clauses via `auth.roles()`. This field controls the PostgreSQL\n * `TO` clause in `CREATE POLICY ... TO role_name`.\n *\n * Use this if you have dedicated PostgreSQL roles (e.g. `app_read`,\n * `app_write`) and want policies to target specific ones.\n *\n * @default [\"public\"]\n *\n * @example\n * // Only apply this policy when connected as `app_role`\n * { operation: \"select\", access: \"public\", pgRoles: [\"app_role\"] }\n */\n pgRoles?: string[];\n}\n\n/**\n * Security rule that grants access based on row ownership.\n * Generates a USING/WITH CHECK clause like: `<column> = auth.uid()`\n *\n * Cannot be combined with `using`, `withCheck`, or `access`.\n *\n * @example\n * { operation: \"all\", ownerField: \"user_id\" }\n *\n * @group Models\n */\nexport interface OwnerSecurityRule extends SecurityRuleBase {\n /** The property (column) that stores the owner's user ID. */\n ownerField: string;\n access?: never;\n using?: never;\n withCheck?: never;\n}\n\n/**\n * Security rule that grants unrestricted row access (no row filtering).\n * Generates `USING (true)`.\n *\n * This means \"no row-level filter\", NOT \"anonymous/unauthenticated access\".\n * Authentication is still enforced at the API layer — this only controls which\n * *rows* authenticated users can see.\n *\n * Cannot be combined with `using`, `withCheck`, or `ownerField`.\n *\n * @example\n * // Public read (any authenticated user sees all rows)\n * { operation: \"select\", access: \"public\" }\n *\n * @group Models\n */\nexport interface PublicSecurityRule extends SecurityRuleBase {\n /** Grant unrestricted row access for this operation. */\n access: \"public\";\n ownerField?: never;\n using?: never;\n withCheck?: never;\n}\n\n/**\n * Security rule using raw SQL expressions for full PostgreSQL RLS power.\n *\n * Cannot be combined with `ownerField` or `access`.\n *\n * You can reference columns via `{column_name}` which will be resolved to\n * `table.column_name` in the generated Drizzle code.\n *\n * @example\n * // Rows published in the last 30 days are visible\n * { operation: \"select\", using: \"{published_at} > now() - interval '30 days'\" }\n *\n * @example\n * // Only the owner, or users with 'moderator' role\n * {\n * operation: \"select\",\n * using: \"{user_id} = auth.uid() OR auth.roles() ~ 'moderator'\"\n * }\n *\n * @group Models\n */\nexport interface RawSQLSecurityRule extends SecurityRuleBase {\n /**\n * Raw SQL expression for the `USING` clause.\n * This controls which *existing* rows are visible / can be modified / deleted.\n * Applied to SELECT, UPDATE, and DELETE.\n */\n using: string;\n\n /**\n * Raw SQL expression for the `WITH CHECK` clause.\n * This controls which *new/updated* row values are allowed.\n * Applied to INSERT and UPDATE.\n *\n * If not provided on INSERT/UPDATE policies, falls back to `using`\n * (which matches PostgreSQL's own default behavior).\n */\n withCheck?: string;\n\n ownerField?: never;\n access?: never;\n}\n\n/**\n * Security rule that only filters by application roles, without any\n * row-level condition (USING/WITH CHECK).\n *\n * Useful for simple \"only admins can access this table\" rules where\n * no per-row filtering is needed.\n *\n * @example\n * // Only admins can delete\n * { operation: \"delete\", roles: [\"admin\"] }\n *\n * @group Models\n */\nexport interface RolesOnlySecurityRule extends SecurityRuleBase {\n ownerField?: never;\n access?: never;\n using?: never;\n withCheck?: never;\n}\n\n/**\n * Configuration for authentication collections.\n *\n * Controls what happens when admins create users, reset passwords,\n * and which entity actions are auto-injected.\n *\n * Use `auth: true` as sugar for `{ enabled: true }` with all defaults.\n *\n * @example Override user creation\n * ```ts\n * auth: {\n * enabled: true,\n * onCreateUser: async (values, ctx) => {\n * const hash = await ctx.hashPassword(\"welcome123\");\n * return {\n * values: { ...values, passwordHash: hash, emailVerified: true },\n * temporaryPassword: \"welcome123\",\n * };\n * },\n * }\n * ```\n *\n * @example Disable the reset-password entity action\n * ```ts\n * auth: {\n * enabled: true,\n * actions: { resetPassword: false },\n * }\n * ```\n *\n * @group Models\n */\nexport interface AuthCollectionConfig {\n /** Set to true to mark this collection as the authentication collection. */\n enabled: boolean;\n\n /**\n * Called when an admin creates a user via the collection REST API.\n *\n * Default: generate password → hash → normalize email → save →\n * send invitation email (or return temp password if no email configured).\n *\n * Override to implement custom invitation flows, LDAP sync, etc.\n */\n onCreateUser?: (\n values: Record<string, unknown>,\n ctx: AuthCollectionContext\n ) => Promise<AuthCollectionCreateResult>;\n\n /**\n * Called when an admin resets a user's password via the admin panel.\n *\n * Default: generate reset token → send email (or generate + return temp password).\n * Override for custom reset flows.\n */\n onResetPassword?: (\n userId: string,\n ctx: AuthCollectionContext\n ) => Promise<AuthCollectionResetResult>;\n\n /**\n * Control which auth-specific entity actions are auto-injected.\n *\n * Default: `{ resetPassword: true }` — the framework auto-injects\n * the built-in `resetPasswordAction` into the collection's entity actions.\n *\n * Set to `false` to disable, or pass a custom `EntityAction` to replace the UI.\n */\n actions?: {\n resetPassword?: boolean | EntityAction;\n };\n}\n\n/**\n * Context provided to collection-level auth hooks.\n *\n * This is a simplified facade over the server internals —\n * it exposes only what's needed for custom auth flows without\n * coupling collection config to internal interfaces.\n *\n * @group Models\n */\nexport interface AuthCollectionContext {\n /** Hash a password using the configured algorithm (scrypt by default). */\n hashPassword: (password: string) => Promise<string>;\n /** Send an email. Only available when email service is configured. */\n sendEmail?: (options: { to: string; subject: string; html: string; text?: string }) => Promise<void>;\n /** Whether the email service is configured and available. */\n emailConfigured: boolean;\n /** The app name from email config (for templates). */\n appName: string;\n /** The base URL for password reset links. */\n resetPasswordUrl: string;\n}\n\n/**\n * Result of a collection-level `onCreateUser` hook.\n * @group Models\n */\nexport interface AuthCollectionCreateResult {\n /** Processed values to persist (must include passwordHash, NOT raw password). */\n values: Record<string, unknown>;\n /** If set, shown to the admin in the creation result dialog. */\n temporaryPassword?: string;\n /** Whether an invitation email was sent. */\n invitationSent?: boolean;\n}\n\n/**\n * Result of a collection-level `onResetPassword` hook.\n * @group Models\n */\nexport interface AuthCollectionResetResult {\n /** If set, shown to the admin. */\n temporaryPassword?: string;\n /** Whether a reset email was sent. */\n invitationSent?: boolean;\n}\n","import type { EntityCollection } from \"./collections\";\n\n/**\n * @group Models\n */\nexport type OnAction = \"cascade\" | \"restrict\" | \"no action\" | \"set null\" | \"set default\";\n\n/**\n * Extended relation that combines base relation with Rebase UI config\n * @group Models\n */\nexport interface Relation {\n /**\n * The application-level name for this relationship.\n * If not provided, it will be inferred from the target collection path.\n * @example \"posts\"\n */\n relationName?: string;\n\n /**\n * The final collection you want to retrieve records from.\n */\n target: (() => EntityCollection) | any;\n\n /**\n * The nature of the relationship, determining if one or many records are returned.\n */\n cardinality: \"one\" | \"many\";\n\n /**\n * Which side owns the persistence for this relationship.\n * - \"owning\": The foreign key (for one-to-one/many-to-one) or the junction table (for many-to-many) is managed by this collection.\n * - \"inverse\": The foreign key is on the target collection's table. This side of the relation is typically read-only.\n * Defaults to \"owning\".\n */\n direction?: \"owning\" | \"inverse\";\n\n /**\n * The name of the inverse relation.\n * This is only needed when the inverse relation is not the same as the relation name.\n * For example, if the relation name is \"posts\", the inverse relation name might be \"author\".\n */\n inverseRelationName?: string\n\n /**\n * Column on THIS table that stores the foreign key to the target.\n * Required when `direction` is \"owning\" and `cardinality` is \"one\".\n * @example \"author_id\"\n */\n localKey?: string;\n\n /**\n * Column on the TARGET table that stores the foreign key to this entity.\n * Required when `direction` is \"inverse\".\n * @example \"post_id\"\n */\n foreignKeyOnTarget?: string;\n\n /**\n * Defines the junction table for a many-to-many relationship.\n * Required when `cardinality` is \"many\" and `direction` is \"owning\".\n *\n * @example Simple many-to-many between Users and Roles:\n * ```typescript\n * // Users collection\n * {\n * relations: [{\n * relationName: \"roles\",\n * target: () => rolesCollection,\n * cardinality: \"many\",\n * through: {\n * table: \"user_roles\", // Junction table name\n * sourceColumn: \"user_id\", // Column that references this collection's ID\n * targetColumn: \"role_id\" // Column that references target collection's ID\n * }\n * }]\n * }\n *\n * // This creates a junction table like:\n * // CREATE TABLE user_roles (\n * // user_id INTEGER REFERENCES users(id),\n * // role_id INTEGER REFERENCES roles(id),\n * // PRIMARY KEY (user_id, role_id)\n * // );\n * ```\n *\n * @example Many-to-many with additional junction table data:\n * ```typescript\n * // Students and Courses with enrollment date\n * {\n * relations: [{\n * relationName: \"courses\",\n * target: () => coursesCollection,\n * cardinality: \"many\",\n * through: {\n * table: \"enrollments\",\n * sourceColumn: \"student_id\",\n * targetColumn: \"course_id\"\n * }\n * }]\n * }\n *\n * // Junction table can have additional columns:\n * // CREATE TABLE enrollments (\n * // student_id INTEGER REFERENCES students(id),\n * // course_id INTEGER REFERENCES courses(id),\n * // enrolled_at TIMESTAMP DEFAULT NOW(),\n * // grade VARCHAR(2),\n * // PRIMARY KEY (student_id, course_id)\n * // );\n * ```\n */\n through?: {\n table: string;\n sourceColumn: string; // FK to \"this\" collection's PK\n targetColumn: string; // FK to the target collection's PK\n };\n\n /**\n * An explicit, ordered array of JOINs to perform to get from the source\n * to the target. Used for multi-hop relations, composite keys, or when you need\n * fine-grained control over the join logic.\n *\n * When `joinPath` is provided, it overrides all other relation configuration\n * (localKey, foreignKeyOnTarget, through) and gives you complete control\n * over how tables are joined together.\n *\n * @example Simple one-to-one join (equivalent to localKey):\n * ```typescript\n * // Posts -> Authors relationship\n * {\n * relationName: \"author\",\n * target: () => authorsCollection,\n * cardinality: \"one\",\n * joinPath: [\n * {\n * table: \"authors\",\n * on: {\n * from: \"author_id\", // Column on posts table\n * to: \"id\" // Column on authors table\n * }\n * }\n * ]\n * }\n *\n * // Generates: SELECT * FROM posts JOIN authors ON posts.author_id = authors.id\n * ```\n *\n * @example Multi-hop relationship (3 tables):\n * ```typescript\n * // Users -> Permissions through Roles\n * {\n * relationName: \"permissions\",\n * target: () => permissionsCollection,\n * cardinality: \"many\",\n * joinPath: [\n * {\n * table: \"user_roles\",\n * on: {\n * from: \"id\", // users.id\n * to: \"user_id\" // user_roles.user_id\n * }\n * },\n * {\n * table: \"roles\",\n * on: {\n * from: \"role_id\", // user_roles.role_id\n * to: \"id\" // roles.id\n * }\n * },\n * {\n * table: \"role_permissions\",\n * on: {\n * from: \"id\", // roles.id\n * to: \"role_id\" // role_permissions.role_id\n * }\n * },\n * {\n * table: \"permissions\",\n * on: {\n * from: \"permission_id\", // role_permissions.permission_id\n * to: \"id\" // permissions.id\n * }\n * }\n * ]\n * }\n *\n * // Generates:\n * // SELECT * FROM users\n * // JOIN user_roles ON users.id = user_roles.user_id\n * // JOIN roles ON user_roles.role_id = roles.id\n * // JOIN role_permissions ON roles.id = role_permissions.role_id\n * // JOIN permissions ON role_permissions.permission_id = permissions.id\n * ```\n *\n * @example Composite key relationship:\n * ```typescript\n * // Orders -> Customer by company_code + region\n * {\n * relationName: \"customer\",\n * target: () => customersCollection,\n * cardinality: \"one\",\n * joinPath: [\n * {\n * table: \"customers\",\n * on: {\n * from: [\"company_code\", \"region_id\"], // Multiple columns from orders\n * to: [\"code\", \"region_id\"] // Multiple columns on customers\n * }\n * }\n * ]\n * }\n *\n * // Generates:\n * // SELECT * FROM orders\n * // JOIN customers ON orders.company_code = customers.code\n * // AND orders.region_id = customers.region_id\n * ```\n *\n * @example Self-referencing with intermediate table:\n * ```typescript\n * // Users -> Friends (many-to-many self-reference)\n * {\n * relationName: \"friends\",\n * target: () => usersCollection, // Same collection\n * cardinality: \"many\",\n * joinPath: [\n * {\n * table: \"friendships\",\n * on: {\n * from: \"id\", // users.id\n * to: \"user_id\" // friendships.user_id\n * }\n * },\n * {\n * table: \"users\",\n * on: {\n * from: \"friend_id\", // friendships.friend_id\n * to: \"id\" // users.id (target)\n * }\n * }\n * ]\n * }\n * ```\n *\n * @example Complex business logic join:\n * ```typescript\n * // Products -> Active Suppliers (only current, non-expired contracts)\n * {\n * relationName: \"activeSuppliers\",\n * target: () => suppliersCollection,\n * cardinality: \"many\",\n * joinPath: [\n * {\n * table: \"product_supplier_contracts\",\n * on: {\n * from: \"id\", // products.id\n * to: \"product_id\" // contracts.product_id\n * }\n * },\n * {\n * table: \"suppliers\",\n * on: {\n * from: \"supplier_id\", // contracts.supplier_id\n * to: \"id\" // suppliers.id\n * }\n * }\n * ]\n * // Note: Additional WHERE conditions for active/non-expired\n * // would be handled in the query logic, not in joinPath\n * }\n * ```\n */\n joinPath?: JoinStep[];\n\n /**\n * Action to perform on update.\n */\n onUpdate?: OnAction;\n /**\n * Action to perform on delete.\n */\n onDelete?: OnAction;\n\n overrides?: Partial<EntityCollection>;\n\n validation?: {\n required?: boolean;\n }\n}\n\n/**\n * Defines a single, explicit step in a multi-join path.\n *\n * Each step represents one JOIN operation in the sequence. The `from` columns\n * refer to the previous table in the chain (or the source table for the first step),\n * and the `to` columns refer to the current table being joined.\n *\n * @example Single column join:\n * ```typescript\n * {\n * table: \"authors\",\n * on: {\n * from: \"author_id\", // Column from previous table (e.g., posts.author_id)\n * to: \"id\" // Column from current table (authors.id)\n * }\n * }\n * ```\n *\n * @example Multi-column composite key join:\n * ```typescript\n * {\n * table: \"order_items\",\n * on: {\n * from: [\"order_id\", \"store_id\"], // Multiple columns from previous table\n * to: [\"order_id\", \"store_id\"] // Corresponding columns in current table\n * }\n * }\n * ```\n */\nexport interface JoinStep {\n /**\n * The database table name to join TO in this step.\n * This is the table you're joining into, not the table you're joining from.\n *\n * @example \"authors\", \"user_roles\", \"product_categories\"\n */\n table: string;\n\n /**\n * The join condition for this step. Defines how the previous table\n * connects to the current table.\n *\n * - `from`: Column name(s) on the PREVIOUS table in the join chain\n * - `to`: Column name(s) on the CURRENT table (specified in `table`)\n *\n * For the first step, `from` refers to the source collection's table.\n * For subsequent steps, `from` refers to the table from the previous step.\n *\n * Both `from` and `to` support:\n * - Single column: `\"user_id\"`\n * - Multiple columns: `[\"company_id\", \"region_id\"]` for composite keys\n *\n * When using arrays, both `from` and `to` must have the same length,\n * and columns are matched by position (index 0 with index 0, etc.).\n */\n on: {\n from: string | string[];\n to: string | string[];\n };\n}\n","/**\n * @group Models\n */\nexport type Locale =\n \"af\" |\n \"ar\" |\n \"arDZ\" |\n \"arMA\" |\n \"arSA\" |\n \"az\" |\n \"be\" |\n \"bg\" |\n \"bn\" |\n \"ca\" |\n \"cs\" |\n \"cy\" |\n \"da\" |\n \"de\" |\n \"el\" |\n \"enAU\" |\n \"enCA\" |\n \"enGB\" |\n \"enIN\" |\n \"enNZ\" |\n \"enUS\" |\n \"eo\" |\n \"es\" |\n \"et\" |\n \"eu\" |\n \"faIR\" |\n \"fi\" |\n \"fil\" |\n \"fr\" |\n \"frCA\" |\n \"frCH\" |\n \"gd\" |\n \"gl\" |\n \"gu\" |\n \"he\" |\n \"hi\" |\n \"hr\" |\n \"hu\" |\n \"hy\" |\n \"id\" |\n \"is\" |\n \"it\" |\n \"ja\" |\n \"ka\" |\n \"kk\" |\n \"kn\" |\n \"ko\" |\n \"lb\" |\n \"lt\" |\n \"lv\" |\n \"mk\" |\n \"ms\" |\n \"mt\" |\n \"nb\" |\n \"nl\" |\n \"nlBE\" |\n \"nn\" |\n \"pl\" |\n \"pt\" |\n \"ptBR\" |\n \"ro\" |\n \"ru\" |\n \"sk\" |\n \"sl\" |\n \"sr\" |\n \"srLatn\" |\n \"sv\" |\n \"ta\" |\n \"te\" |\n \"th\" |\n \"tr\" |\n \"ug\" |\n \"uk\" |\n \"uz\" |\n \"vi\" |\n \"zhCN\" |\n \"zhTW\";\n","import { Entity } from \"./entities\";\n\n/**\n * @group Models\n */\nexport type EntityLinkBuilder<M extends Record<string, unknown> = Record<string, unknown>> = ({ entity }: {\n entity: Entity<M>\n}) => string;\n","import type { User } from \"../users\";\n\n/**\n * Result of creating a new user via admin flow.\n * Contains the created user plus information about how credentials were delivered.\n */\nexport interface UserCreationResult<USER extends User = User> {\n /** The created user */\n user: USER;\n /** Whether an invitation email was sent to the user */\n invitationSent: boolean;\n /**\n * Temporary password (only present when email service is not configured).\n * This is returned one-time and should be shown to the admin to share manually.\n */\n temporaryPassword?: string;\n}\n","import type { EntityCollection } from \"./collections\";\nimport type { Entity, EntityStatus, EntityValues } from \"./entities\";\nimport type { User } from \"../users\";\nimport type { RebaseCallContext } from \"../rebase_context\";\n\n/**\n * This interface defines all the callbacks that can be used when an entity\n * is being created, updated or deleted.\n * Useful for adding your own logic or blocking the execution of the operation.\n * @group Models\n */\nexport type EntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> = {\n\n /**\n * Callback used after fetching data\n * @param props\n */\n afterRead?(props: EntityAfterReadProps<M, USER>)\n : Promise<Entity<M>> | Entity<M>;\n\n\n /**\n * Callback used before saving, you need to return the values that will get\n * saved. If you throw an error in this method the process stops, and an\n * error snackbar gets displayed.\n * This runs after schema validation.\n * @param props\n */\n beforeSave?(props: EntityBeforeSaveProps<M, USER>)\n : Promise<Partial<EntityValues<M>>> | Partial<EntityValues<M>>;\n\n /**\n * Callback used when save is successful\n * @param props\n */\n afterSave?(props: EntityAfterSaveProps<M, USER>)\n : Promise<void> | void;\n\n /**\n * Callback used when saving fails\n * @param props\n */\n afterSaveError?(props: EntityAfterSaveErrorProps<M, USER>)\n : Promise<void> | void;\n\n /**\n * Callback used before the entity is deleted.\n * If you throw an error in this method the process stops, and an\n * error snackbar gets displayed.\n *\n * @param props\n */\n beforeDelete?(props: EntityBeforeDeleteProps<M, USER>): Promise<boolean | void> | boolean | void;\n\n /**\n * Callback used after the entity is deleted.\n *\n * @param props\n */\n afterDelete?(props: EntityAfterDeleteProps<M, USER>): void;\n\n}\n\n/**\n * Parameters passed to hooks when an entity is fetched\n * @group Models\n */\nexport interface EntityAfterReadProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n\n /**\n * Collection of the entity\n */\n collection: EntityCollection<M>;\n\n /**\n * Full path of the CMS where this collection is being fetched.\n * Might contain unresolved aliases.\n */\n path: string;\n\n /**\n * Fetched entity\n */\n entity: Entity<M>\n\n /**\n * Context of the app status\n */\n context: RebaseCallContext<USER>;\n}\n\n/**\n * Parameters passed to hooks before an entity is saved\n * @group Models\n */\nexport type EntityBeforeSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =\n Omit<EntityAfterSaveProps<M, USER>, \"entityId\">\n & {\n entityId?: string | number;\n }\n/**\n * Parameters passed to hooks before an entity is saved\n * @group Models\n */\nexport type EntityAfterSaveErrorProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> =\n Omit<EntityAfterSaveProps<M, USER>, \"entityId\">\n & {\n entityId?: string | number;\n }\n\n/**\n * Parameters passed to hooks when an entity is saved\n * @group Models\n */\nexport interface EntityAfterSaveProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n\n /**\n * Resolved collection of the entity\n */\n collection: EntityCollection<M>;\n\n /**\n * Full path of the CMS where this entity is being saved.\n * Might contain unresolved aliases.\n */\n path: string;\n\n /**\n * ID of the entity\n */\n entityId: string | number;\n\n /**\n * Values being saved\n */\n values: Partial<EntityValues<M>>;\n\n /**\n * Previous values\n */\n previousValues?: Partial<EntityValues<M>>;\n\n /**\n * New or existing entity\n */\n status: EntityStatus;\n\n /**\n * Context of the app status\n */\n context: RebaseCallContext<USER>;\n}\n\n/**\n * Parameters passed to hooks when an entity is deleted\n * @group Models\n */\nexport interface EntityBeforeDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n\n /**\n * collection of the entity being deleted\n */\n collection: EntityCollection<M>;\n\n /**\n * Path of the parent collection\n */\n path: string;\n\n /**\n * Deleted entity id\n */\n entityId: string | number;\n\n /**\n * Deleted entity\n */\n entity: Entity<M>;\n\n /**\n * Context of the app status\n */\n context: RebaseCallContext<USER>;\n}\n\n/**\n * Parameters passed to hooks after an entity is deleted\n * @group Models\n */\nexport interface EntityAfterDeleteProps<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n\n /**\n * collection of the entity being deleted\n */\n collection: EntityCollection<M>;\n\n /**\n * Path of the parent collection\n */\n path: string;\n\n /**\n * Deleted entity id\n */\n entityId: string | number;\n\n /**\n * Deleted entity\n */\n entity: Entity<M>;\n\n /**\n * Context of the app status\n */\n context: RebaseCallContext<USER>;\n}\n\n","import type { DataDriver } from \"../controllers/data_driver\";\nimport type { StorageSource } from \"../controllers/storage\";\n\nexport type EntityOverrides = {\n /**\n * Internal driver override for this collection.\n * Used by the CMS engine to route data operations.\n */\n driver?: DataDriver;\n storageSource?: StorageSource;\n};\n","import type { Entity } from \"./entities\";\nimport type { User } from \"../users\";\nimport type { RebaseContext } from \"../rebase_context\";\n\n/**\n * You can use this configuration to add additional fields to the data\n * exports\n * @group Models\n */\nexport interface ExportConfig<USER extends User = User> {\n additionalFields: ExportMappingFunction<USER>[];\n}\n\n/**\n * @group Models\n */\nexport interface ExportMappingFunction<USER extends User = User> {\n key: string;\n builder: ({\n entity,\n context\n }: {\n entity: Entity,\n context: RebaseContext<USER>\n }) => Promise<string> | string;\n}\n","import { EntityCollection } from \"./collections\";\n\nexport type ModifyCollectionProps = {\n collection: EntityCollection,\n parentPaths: string[],\n};\n","import React, { FormEvent } from \"react\";\n\nexport type FormexController<T = unknown> = {\n values: T;\n initialValues: T;\n setValues: (values: T) => void;\n setFieldValue: (key: string, value: unknown, shouldValidate?: boolean) => void;\n touched: Record<string, boolean>;\n setFieldTouched: (key: string, touched: boolean, shouldValidate?: boolean) => void;\n setTouched: (touched: Record<string, boolean>) => void;\n dirty: boolean;\n setDirty: (dirty: boolean) => void;\n setSubmitCount: (submitCount: number) => void;\n errors: Record<string, string>;\n setFieldError: (key: string, error?: string) => void;\n handleChange: (event: React.SyntheticEvent) => void,\n handleBlur: (event: React.FocusEvent) => void,\n handleSubmit: (event?: FormEvent<HTMLFormElement>) => void;\n validate: () => void;\n resetForm: (props?: FormexResetProps<T>) => void;\n submitCount: number;\n isSubmitting: boolean;\n setSubmitting: (isSubmitting: boolean) => void;\n isValidating: boolean;\n /**\n * The version of the form. This is incremented every time the form is reset\n * or the form is submitted.\n */\n version: number;\n\n debugId?: string;\n\n undo: () => void;\n redo: () => void;\n\n canUndo: boolean;\n canRedo: boolean;\n}\n\nexport type FormexResetProps<T = unknown> = {\n values?: T;\n submitCount?: number;\n errors?: Record<string, string>;\n touched?: Record<string, boolean>;\n};\n","import { Entity } from \"./entities\";\n\nexport interface WebSocketErrorPayload {\n error?: string | { message: string; code?: string };\n message?: string;\n code?: string;\n}\n\nexport interface WebSocketMessage {\n type: string;\n payload?: unknown;\n subscriptionId?: string;\n requestId?: string;\n entities?: Entity<Record<string, unknown>>[];\n entity?: Entity<Record<string, unknown>> | null;\n error?: string;\n}\n\nexport interface CollectionUpdateMessage extends WebSocketMessage {\n type: \"collection_update\";\n subscriptionId: string;\n entities: Entity<Record<string, unknown>>[];\n}\n\nexport interface EntityUpdateMessage extends WebSocketMessage {\n type: \"entity_update\";\n subscriptionId: string;\n entity: Entity<Record<string, unknown>> | null;\n}\n\n/**\n * Lightweight patch message sent to collection subscribers when a single\n * entity is created, updated, or deleted. The client can merge this into\n * its cached collection data for near-instant cross-tab updates without\n * waiting for a full collection refetch.\n */\nexport interface CollectionEntityPatchMessage extends WebSocketMessage {\n type: \"collection_entity_patch\";\n subscriptionId: string;\n entityId: string;\n /** The updated entity, or null if deleted */\n entity: Entity<Record<string, unknown>> | null;\n}\n\n/**\n * Column metadata returned by table introspection.\n */\nexport interface TableColumnInfo {\n column_name: string;\n data_type: string;\n udt_name: string;\n is_nullable: string;\n column_default: string | null;\n character_maximum_length: number | null;\n /** Enum values, populated for USER-DEFINED (enum) columns */\n enum_values?: string[];\n}\n\nexport interface TableForeignKeyInfo {\n column_name: string;\n foreign_table_name: string;\n foreign_column_name: string;\n}\n\nexport interface TableJunctionInfo {\n junction_table_name: string;\n source_column_name: string;\n target_table_name: string;\n target_column_name: string;\n}\n\nexport interface TablePolicyInfo {\n policy_name: string;\n roles: string[];\n cmd: string;\n qual?: string;\n with_check?: string;\n}\n\nexport interface TableMetadata {\n columns: TableColumnInfo[];\n foreignKeys: TableForeignKeyInfo[];\n junctions: TableJunctionInfo[];\n policies: TablePolicyInfo[];\n}\n","import type { Entity } from \"./entities\";\nimport type { EntityCollection, FilterValues, WhereFilterOp } from \"./collections\";\nimport type { AuthAdapter } from \"./auth_adapter\";\n\n// =============================================================================\n// DATABASE CONNECTION INTERFACES\n// =============================================================================\n\n/**\n * Abstract database connection interface.\n * Represents a connection to any database system.\n */\nexport interface DatabaseConnection {\n /**\n * Type identifier for this database (e.g., 'postgres', 'mongodb', 'mysql')\n */\n readonly type: string;\n\n /**\n * Whether the connection is currently active\n */\n readonly isConnected?: boolean;\n\n /**\n * Close the database connection and release resources.\n */\n close?(): Promise<void>;\n}\n\n// =============================================================================\n// QUERY BUILDING INTERFACES\n// =============================================================================\n\n/**\n * A single filter condition for database queries\n */\nexport interface QueryFilter {\n field: string;\n operator: WhereFilterOp;\n value: unknown;\n}\n\n/**\n * Options for fetching a collection of entities\n */\nexport interface FetchCollectionOptions<M extends Record<string, unknown> = Record<string, unknown>> {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: unknown;\n searchString?: string;\n databaseId?: string;\n collection?: EntityCollection;\n}\n\n/**\n * Options for searching entities\n */\nexport interface SearchOptions<M extends Record<string, unknown> = Record<string, unknown>> {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n databaseId?: string;\n collection?: EntityCollection;\n}\n\n/**\n * Options for counting entities\n */\nexport interface CountOptions<M extends Record<string, unknown> = Record<string, unknown>> {\n filter?: FilterValues<Extract<keyof M, string>>;\n searchString?: string;\n databaseId?: string;\n}\n\n/**\n * Abstract condition builder interface.\n * Implementations translate Rebase filter conditions to database-specific queries.\n *\n * Note: This interface can be implemented as instance methods or as a class with static methods.\n * For static implementations (like DrizzleConditionBuilder), use the ConditionBuilderStatic type.\n *\n * @template T The type of condition returned by the builder (e.g., SQL for PostgreSQL, Filter<Document> for MongoDB)\n */\nexport interface ConditionBuilder<T = unknown> {\n /**\n * Build filter conditions from Rebase FilterValues\n */\n buildFilterConditions<M extends Record<string, unknown>>(\n filter: FilterValues<Extract<keyof M, string>>,\n collectionPath: string,\n ...args: unknown[]\n ): T[];\n\n /**\n * Build search conditions for text search\n */\n buildSearchConditions(\n searchString: string,\n properties: Record<string, unknown>,\n ...args: unknown[]\n ): T[];\n\n /**\n * Combine multiple conditions with AND operator\n */\n combineConditionsWithAnd(conditions: T[]): T | undefined;\n\n /**\n * Combine multiple conditions with OR operator\n */\n combineConditionsWithOr(conditions: T[]): T | undefined;\n}\n\n/**\n * Static condition builder type for implementations using static methods.\n * Use this type when the class provides static methods rather than instance methods.\n *\n * @example\n * // DrizzleConditionBuilder satisfies this type\n * const builder: ConditionBuilderStatic<SQL> = DrizzleConditionBuilder;\n */\nexport type ConditionBuilderStatic<T = unknown> = {\n buildFilterConditions<M extends Record<string, unknown>>(\n filter: FilterValues<Extract<keyof M, string>>,\n ...args: unknown[]\n ): T[];\n buildSearchConditions(\n searchString: string,\n properties: Record<string, unknown>,\n ...args: unknown[]\n ): T[];\n combineConditionsWithAnd(conditions: T[]): T | undefined;\n combineConditionsWithOr(conditions: T[]): T | undefined;\n};\n\n// =============================================================================\n// ENTITY REPOSITORY INTERFACES\n// =============================================================================\n\n/**\n * Abstract entity repository interface.\n * Handles all CRUD operations for entities in the database.\n *\n * Implementations should handle:\n * - Entity serialization/deserialization\n * - Relation resolution\n * - ID generation and conversion\n */\nexport interface EntityRepository {\n /**\n * Fetch a single entity by ID\n */\n fetchEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n entityId: string | number,\n databaseId?: string\n ): Promise<Entity<M> | undefined>;\n\n /**\n * Fetch a collection of entities with optional filtering, ordering, and pagination\n */\n fetchCollection<M extends Record<string, unknown>>(\n collectionPath: string,\n options?: FetchCollectionOptions<M>\n ): Promise<Entity<M>[]>;\n\n /**\n * Search entities by text\n */\n searchEntities<M extends Record<string, unknown>>(\n collectionPath: string,\n searchString: string,\n options?: SearchOptions<M>\n ): Promise<Entity<M>[]>;\n\n /**\n * Count entities in a collection\n */\n countEntities<M extends Record<string, unknown>>(\n collectionPath: string,\n options?: CountOptions<M>\n ): Promise<number>;\n\n /**\n * Save an entity (create or update)\n */\n saveEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n values: Partial<M>,\n entityId?: string | number,\n databaseId?: string\n ): Promise<Entity<M>>;\n\n /**\n * Delete an entity by ID\n */\n deleteEntity(\n collectionPath: string,\n entityId: string | number,\n databaseId?: string\n ): Promise<void>;\n\n /**\n * Check if a field value is unique in a collection\n */\n checkUniqueField(\n collectionPath: string,\n fieldName: string,\n value: unknown,\n excludeEntityId?: string,\n databaseId?: string\n ): Promise<boolean>;\n\n}\n\n// =============================================================================\n// REALTIME INTERFACES\n// =============================================================================\n\n/**\n * Configuration for subscribing to a collection\n */\nexport interface CollectionSubscriptionConfig {\n clientId: string;\n path: string;\n filter?: unknown;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: unknown;\n databaseId?: string;\n searchString?: string;\n}\n\n/**\n * Configuration for subscribing to a single entity\n */\nexport interface EntitySubscriptionConfig {\n clientId: string;\n path: string;\n entityId: string | number;\n}\n\n/**\n * Abstract realtime provider interface.\n * Handles real-time subscriptions and notifications for entity changes.\n */\nexport interface RealtimeProvider {\n /**\n * Subscribe to collection changes\n */\n subscribeToCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig,\n callback?: (entities: Entity[]) => void\n ): void;\n\n /**\n * Subscribe to single entity changes\n */\n subscribeToEntity(\n subscriptionId: string,\n config: EntitySubscriptionConfig,\n callback?: (entity: Entity | null) => void\n ): void;\n\n /**\n * Unsubscribe from a subscription\n */\n unsubscribe(subscriptionId: string): void;\n\n /**\n * Notify all relevant subscribers of an entity update\n */\n notifyEntityUpdate(\n path: string,\n entityId: string,\n entity: Entity | null,\n databaseId?: string\n ): Promise<void>;\n\n /**\n * Called when the HTTP server is ready and listening.\n * Useful for providers that need the server address for callbacks.\n */\n onServerReady?(serverInfo: { port: number; hostname?: string }): void;\n\n /**\n * Gracefully shut down the realtime provider.\n * Called during server shutdown to clean up resources.\n */\n destroy?(): Promise<void>;\n\n /**\n * Stop the internal LISTEN client (e.g., PostgreSQL LISTEN/NOTIFY).\n * Called during graceful shutdown before closing database connections.\n */\n stopListening?(): Promise<void>;\n}\n\n// =============================================================================\n// COLLECTION REGISTRY INTERFACES\n// =============================================================================\n\n/**\n * Abstract collection registry interface.\n * Manages registration and lookup of entity collections.\n */\nexport interface CollectionRegistryInterface {\n /**\n * Register a collection\n */\n register(collection: EntityCollection): void;\n\n /**\n * Get a collection by its path\n */\n getCollectionByPath(path: string): EntityCollection | undefined;\n\n /**\n * Get all registered collections\n */\n getCollections(): EntityCollection[];\n}\n\n// =============================================================================\n// DATA TRANSFORMER INTERFACES\n// =============================================================================\n\n/**\n * Abstract data transformer interface.\n * Handles serialization/deserialization between frontend and database formats.\n */\nexport interface DataTransformer {\n /**\n * Transform entity data for storage in the database\n */\n serializeToDatabase<M extends Record<string, unknown>>(\n entity: M,\n collection: EntityCollection\n ): Record<string, unknown>;\n\n /**\n * Transform database data back to entity format\n */\n deserializeFromDatabase<M extends Record<string, unknown>>(\n data: Record<string, unknown>,\n collection: EntityCollection\n ): Promise<M>;\n}\n\n// =============================================================================\n// DATABASE ADMIN — CAPABILITY-SPECIFIC INTERFACES (1.3)\n// =============================================================================\n\n/**\n * Administrative operations for SQL-based databases (PostgreSQL, MySQL, etc.).\n * Used by the SQL Editor, RLS Editor, and schema browser.\n *\n * @group Admin\n */\nexport interface SQLAdmin {\n /**\n * Execute raw SQL against the database.\n */\n executeSql(sql: string, options?: { database?: string; role?: string }): Promise<Record<string, unknown>[]>;\n\n /**\n * Fetch the available databases on the server.\n */\n fetchAvailableDatabases?(): Promise<string[]>;\n\n /**\n * Fetch the available database roles.\n */\n fetchAvailableRoles?(): Promise<string[]>;\n\n /**\n * Fetch the current database name.\n */\n fetchCurrentDatabase?(): Promise<string | undefined>;\n}\n\n/**\n * Administrative operations for document-based databases (MongoDB, Firestore, etc.).\n * Used by future document administration tools.\n *\n * @group Admin\n */\nexport interface DocumentAdmin {\n /**\n * Execute an aggregation pipeline or equivalent query.\n */\n executeAggregate?(pipeline: Record<string, unknown>[]): Promise<Record<string, unknown>[]>;\n\n /**\n * Fetch statistics for a collection (document count, size, etc.).\n */\n fetchCollectionStats?(collectionName: string): Promise<{ count: number; sizeBytes?: number }>;\n}\n\n/**\n * Administrative operations for schema management.\n * Shared across SQL and document databases.\n *\n * @group Admin\n */\nexport interface SchemaAdmin {\n /**\n * Fetch database tables/collections not yet mapped to a Rebase collection.\n */\n fetchUnmappedTables?(mappedPaths?: string[]): Promise<string[]>;\n\n /**\n * Fetch column/field metadata for a single table/collection.\n * The return type is generic — SQL backends return TableMetadata,\n * document backends may return a different shape.\n */\n fetchTableMetadata?(tableName: string): Promise<unknown>;\n}\n\n/**\n * Metadata for a database branch.\n * @group Admin\n */\nexport interface BranchInfo {\n /** Branch name (without prefix). */\n name: string;\n /** The database this branch was created from. */\n parentDatabase: string;\n /** When the branch was created. */\n createdAt: Date;\n /** Size in bytes, if available from the server. */\n sizeBytes?: number;\n}\n\n/**\n * Administrative operations for database branching.\n * Allows creating isolated database copies for development/preview workflows.\n *\n * @group Admin\n */\nexport interface BranchAdmin {\n /** Create a new branch (database copy) from the current or specified source database. */\n createBranch(name: string, options?: { source?: string }): Promise<BranchInfo>;\n\n /** Delete a branch database. Cannot delete the main/default database. */\n deleteBranch(name: string): Promise<void>;\n\n /** List all branches (databases that were created via branching). */\n listBranches(): Promise<BranchInfo[]>;\n\n /** Get info about a specific branch. */\n getBranchInfo(name: string): Promise<BranchInfo | undefined>;\n}\n\n/**\n * Union type for all admin capabilities.\n * A backend may implement any combination of these interfaces.\n *\n * Use type guards (`isSQLAdmin`, `isDocumentAdmin`, `isSchemaAdmin`, `isBranchAdmin`)\n * to safely narrow the type before calling methods.\n *\n * @group Admin\n */\nexport type DatabaseAdmin = Partial<SQLAdmin> & Partial<DocumentAdmin> & Partial<SchemaAdmin> & Partial<BranchAdmin>;\n\n/**\n * Type guard: does this admin support SQL operations?\n * @group Admin\n */\nexport function isSQLAdmin(admin: DatabaseAdmin | undefined): admin is SQLAdmin {\n return !!admin && typeof (admin as SQLAdmin).executeSql === \"function\";\n}\n\n/**\n * Type guard: does this admin support document operations?\n * @group Admin\n */\nexport function isDocumentAdmin(admin: DatabaseAdmin | undefined): admin is DocumentAdmin {\n return !!admin && (\n typeof (admin as DocumentAdmin).executeAggregate === \"function\" ||\n typeof (admin as DocumentAdmin).fetchCollectionStats === \"function\"\n );\n}\n\n/**\n * Type guard: does this admin support schema management?\n * @group Admin\n */\nexport function isSchemaAdmin(admin: DatabaseAdmin | undefined): admin is SchemaAdmin {\n return !!admin && (\n typeof (admin as SchemaAdmin).fetchUnmappedTables === \"function\" ||\n typeof (admin as SchemaAdmin).fetchTableMetadata === \"function\"\n );\n}\n\n/**\n * Type guard: does this admin support database branching?\n * @group Admin\n */\nexport function isBranchAdmin(admin: DatabaseAdmin | undefined): admin is BranchAdmin {\n return !!admin && typeof (admin as BranchAdmin).createBranch === \"function\";\n}\n\n// =============================================================================\n// LIFECYCLE INTERFACES (1.4)\n// =============================================================================\n\n/**\n * Health check result returned by `healthCheck()`.\n * @group Lifecycle\n */\nexport interface HealthCheckResult {\n /** Whether the backend is healthy and able to serve requests. */\n healthy: boolean;\n /** Round-trip latency to the database in milliseconds. */\n latencyMs: number;\n /** Optional details (e.g., pool stats, replication lag). */\n details?: Record<string, unknown>;\n}\n\n/**\n * Lifecycle contract for backend components that hold resources\n * (database connections, WebSocket pools, timers, etc.).\n *\n * All methods are optional — simple backends (e.g., in-memory) can skip them.\n * @group Lifecycle\n */\nexport interface BackendLifecycle {\n /**\n * Initialize the backend: open connections, run migrations, seed data.\n * Called once during startup. Idempotent.\n */\n initialize?(): Promise<void>;\n\n /**\n * Check whether the backend is healthy and reachable.\n * Should be fast (< 1 s) and safe to call frequently.\n */\n healthCheck?(): Promise<HealthCheckResult>;\n\n /**\n * Gracefully shut down: close connections, flush buffers, cancel timers.\n * After calling `destroy()`, no other methods should be called.\n */\n destroy?(): Promise<void>;\n}\n\n// =============================================================================\n// BACKEND FACTORY INTERFACES\n// =============================================================================\n\n/**\n * Configuration for creating a database backend\n */\nexport interface BackendConfig {\n /**\n * Type of database backend\n */\n type: string;\n\n /**\n * Database connection (implementation-specific)\n */\n connection: unknown;\n\n /**\n * Schema definition (implementation-specific, e.g., Drizzle schema for PostgreSQL)\n */\n schema?: unknown;\n}\n\n/**\n * A complete backend instance with all required services.\n *\n * Now includes optional lifecycle management and admin capabilities.\n */\nexport interface BackendInstance extends BackendLifecycle {\n /**\n * Entity repository for CRUD operations\n */\n entityRepository: EntityRepository;\n\n /**\n * Realtime provider for subscriptions\n */\n realtimeProvider: RealtimeProvider;\n\n /**\n * Collection registry\n */\n collectionRegistry: CollectionRegistryInterface;\n\n /**\n * The underlying database connection\n */\n connection: DatabaseConnection;\n\n /**\n * Administrative operations (SQL, schema, documents).\n * What's available depends on the backend type — use type guards\n * (`isSQLAdmin`, `isSchemaAdmin`, etc.) to narrow.\n */\n admin?: DatabaseAdmin;\n}\n\n/**\n * Factory function type for creating backend instances\n */\nexport type BackendFactory<TConfig extends BackendConfig = BackendConfig> =\n (config: TConfig) => BackendInstance;\n\n// =============================================================================\n// BACKEND BOOTSTRAPPER (1.2)\n// =============================================================================\n\n/**\n * A `BackendBootstrapper` encapsulates all driver-specific initialization logic.\n *\n * Instead of hard-coding Postgres setup into `initializeRebaseBackend()`,\n * each database backend provides its own bootstrapper that knows how to:\n * - Create the DataDriver from a config object\n * - Optionally initialize auth tables\n * - Optionally create a realtime service\n * - Mount driver-specific API routes\n *\n * The main `initializeRebaseBackend()` becomes a **coordinator** that iterates\n * registered bootstrappers, calls their hooks, and wires the results together.\n *\n * @group Backend\n *\n * @example\n * ```typescript\n * // Third-party MySQL bootstrapper\n * const mysqlBootstrapper: BackendBootstrapper = {\n * type: \"mysql\",\n * initializeDriver: async (config) => new MySQLDataDriver(config.connection),\n * initializeRealtime: async (config) => new MySQLChangeStreamRealtime(config.connection),\n * };\n *\n * initializeRebaseBackend({\n * ...config,\n * bootstrappers: [postgresBootstrapper, mysqlBootstrapper]\n * });\n * ```\n */\nexport interface BackendBootstrapper {\n /**\n * Which driver type this bootstrapper handles.\n * Must match the `type` field on the driver config object\n * (e.g., `\"postgres\"`, `\"mongodb\"`, `\"mysql\"`).\n */\n type: string;\n\n /**\n * Unique identifier for this bootstrapper instance.\n * Used to register the driver in the driver registry.\n * Defaults to `type` if not set.\n */\n id?: string;\n\n /**\n * Whether this bootstrapper provides the default driver.\n * When true, the coordinator uses this driver as the primary one.\n */\n isDefault?: boolean;\n\n /**\n * Run database migrations for this driver.\n * Called by the coordinator after all drivers are initialized.\n */\n runMigrations?(config: unknown, driverResult: InitializedDriver): Promise<void>;\n\n /**\n * Create a DataDriver from the given config.\n * This is the only **required** method.\n */\n initializeDriver(config: unknown): Promise<InitializedDriver>;\n\n /**\n * Initialize auth tables / services if this driver supports them.\n * Return undefined if auth is not supported by this backend.\n */\n initializeAuth?(config: unknown, driverResult: InitializedDriver): Promise<BootstrappedAuth | undefined>;\n\n /**\n * Initialize history tables / services if this driver supports them.\n * Return undefined if history is not supported by this backend.\n */\n initializeHistory?(config: unknown, driverResult: InitializedDriver): Promise<{ historyService: unknown } | undefined>;\n\n /**\n * Create a realtime provider for this driver.\n * Return undefined if the driver does not support realtime.\n */\n initializeRealtime?(config: unknown, driverResult: InitializedDriver): Promise<RealtimeProvider | undefined>;\n\n /**\n * Mount any driver-specific HTTP routes (e.g., custom admin endpoints).\n * Called after all drivers are initialized.\n */\n mountRoutes?(app: unknown, basePath: string, driverResult: InitializedDriver): void;\n\n /**\n * Return admin capabilities for this driver.\n */\n getAdmin?(driverResult: InitializedDriver): DatabaseAdmin | undefined;\n\n /**\n * Initialize WebSocket server for realtime operations.\n */\n initializeWebsockets?(server: unknown, realtimeService: RealtimeProvider, driver: import(\"../controllers/data_driver\").DataDriver, config?: unknown, authAdapter?: AuthAdapter): Promise<void> | void;\n}\n\n/**\n * Result of `BackendBootstrapper.initializeDriver()`.\n * @group Backend\n */\nexport interface InitializedDriver {\n /** The DataDriver instance, ready for use. */\n driver: import(\"../controllers/data_driver\").DataDriver;\n\n /** The realtime service, if the driver created one during init. */\n realtimeProvider?: RealtimeProvider;\n\n /** A collection registry to register schema / tables into. */\n collectionRegistry?: CollectionRegistryInterface;\n\n /** The underlying database connection (for lifecycle management). */\n connection?: DatabaseConnection;\n\n /**\n * Opaque handle that the bootstrapper can use in subsequent hooks\n * (e.g., `initializeAuth`, `mountRoutes`) to access driver internals.\n * Not used by the coordinator.\n */\n internals?: unknown;\n}\n\n/**\n * Result of `BackendBootstrapper.initializeAuth()`.\n * @group Backend\n */\nexport interface BootstrappedAuth {\n /** User management service. */\n userService: unknown;\n /** Role management service (optional, roles are now simple strings). */\n roleService?: unknown;\n /** Email service (optional). */\n emailService?: unknown;\n /** Combined Auth Repository for unified token and user management. */\n authRepository?: unknown;\n}\n","/**\n * Recursively makes all properties optional.\n * Used to type partial translation overrides.\n */\nexport type DeepPartial<T> = T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * All user-visible strings used internally by @rebasepro/core.\n * Pass a `DeepPartial<RebaseTranslations>` via the `translations` prop\n * on your Rebase entry-point component to override any key, or to add\n * a new locale.\n *\n * @group Core\n */\nexport interface RebaseTranslations {\n // ─── Form actions ────────────────────────────────────────────\n save: string;\n create: string;\n /** Used when duplicating an existing entity */\n create_copy: string;\n save_and_close: string;\n create_copy_and_close: string;\n create_and_close: string;\n /** Discard changes on an existing entity */\n discard: string;\n /** Clear a new/copy form (not yet persisted) */\n clear: string;\n cancel: string;\n\n // ─── Entity actions ──────────────────────────────────────────\n edit: string;\n copy: string;\n delete: string;\n delete_not_allowed: string;\n edit_entity?: string;\n back_to_detail?: string;\n\n // ─── Delete dialog ───────────────────────────────────────────\n delete_confirmation_title: string;\n delete_confirmation_body: string;\n delete_multiple_confirmation_body: string;\n\n // ─── Unsaved-changes dialog ───────────────────────────────────\n unsaved_changes_title: string;\n unsaved_changes_body: string;\n discard_changes: string;\n keep_editing: string;\n\n // ─── Collection table / toolbar ──────────────────────────────\n search: string;\n find_by_id: string;\n find_entity_by_id: string;\n filter: string;\n clear_filter: string;\n clear_filter_sort: string;\n clear_sort: string;\n /** Reset all active filters */\n clear_all: string;\n no_items: string;\n no_entries_found: string;\n all_entries_loaded: string;\n create_your_first_entry: string;\n no_results_filter_sort: string;\n /** Shown when a text search yields no results. Supports `{{search}}` interpolation. */\n no_results_search?: string;\n add: string;\n remove: string;\n copy_id: string;\n add_specific: string;\n select_specific: string;\n select_from: string;\n done: string;\n log_out: string;\n column_cannot_be_edited: string;\n close: string;\n unsaved_local_changes: string;\n unsaved_local_changes_description: string;\n preview_changes: string;\n apply_changes: string;\n discard_local_changes: string;\n preview_local_changes: string;\n preview_local_changes_description: string;\n type: string;\n string: string;\n number: string;\n boolean: string;\n date: string;\n map: string;\n array: string;\n arrays_of_arrays_not_supported: string;\n data_type_not_supported: string;\n browser_does_not_support_audio: string;\n user_not_found: string;\n\n // ─── Collection view actions ──────────────────────────────────\n /** \"Delete\" action on collections, may require permissions check */\n delete_selected: string;\n cannot_delete_selected: string;\n\n // ─── Array / field containers ─────────────────────────────────\n /** Label for buttons that add a new item to a list */\n add_entry: string;\n add_on_top: string;\n add_below: string;\n /** Label when a fieldName is provided — \"Add to {fieldName}\" */\n add_to_field: string;\n /** Placeholder for the 'value' input in a KeyValue field */\n value: string;\n /** Placeholder for the 'key' input in a KeyValue field */\n key: string;\n /** Drag and drop help text for multiple files */\n drag_drop_multiple: string;\n /** Drag and drop help text for a single file */\n drag_drop_single: string;\n\n // ─── Navigation / scaffold ────────────────────────────────────\n open_menu: string;\n close_drawer: string;\n navigation_drawer: string;\n collapse: string;\n expand: string;\n /** Tooltip for the language switcher in the drawer footer */\n change_language?: string;\n /** Tooltip for the theme toggle in the drawer footer */\n toggle_theme?: string;\n /** Aria label for the user menu trigger in the drawer footer */\n user_menu?: string;\n\n // ─── Error states ─────────────────────────────────────────────\n error: string;\n error_loading_data?: string;\n error_check_server_logs?: string;\n error_technical_details?: string;\n error_uploading_file: string;\n error_deleting: string;\n error_before_delete: string;\n error_firestore_index: string;\n create_index: string;\n value_is_not_reference: string;\n click_to_edit: string;\n data_is_not_array_of_references: string;\n collection_does_not_exist: string;\n\n // ─── Misc ─────────────────────────────────────────────────────\n loading: string;\n local_changes_applied: string;\n local_changes_discarded: string;\n open_in_console: string;\n see_console_details: string;\n drop_here_create_group: string;\n filter_for_null_values: string;\n value_updated_elsewhere: string;\n add_property: string;\n edit_name: string;\n this_entity_not_exist: string;\n internal_error: string;\n /** Shown in unsaved-changes dialogs */\n are_you_sure_leave: string;\n passkey_error_unsupported: string;\n\n // ─── Entity form feedback ─────────────────────────────────────\n /** Snackbar message after a successful save */\n saved_correctly: string;\n /** Snackbar title when a beforeSave callback throws */\n error_before_saving: string;\n /** Snackbar title when an afterSave callback throws */\n error_after_saving: string;\n /** Snackbar title when the save itself fails */\n error_saving_entity: string;\n /** Alert shown when the entity does not exist in the database */\n entity_does_not_exist: string;\n /** Tooltip when the form has unsaved modifications */\n form_modified: string;\n /** Tooltip when the form is in sync with the database */\n form_in_sync: string;\n\n admin: string;\n home: string;\n this_form_has_errors: string;\n error_loading_navigation: string;\n error_loading_auth: string;\n this_form_has_been_modified: string;\n current_form_in_sync: string;\n unexpected_value: string;\n unexpected_value_click_to_edit: string;\n unexpected_reference_value: string;\n copy_url_to_clipboard: string;\n open_image_in_new_tab: string;\n reference_not_set: string;\n reference_does_not_exist: string;\n entity_not_found: string;\n file_not_found: string;\n unsaved_changes_in_entity: string;\n delete_this_role: string;\n no_roles_yet: string;\n create_default_roles: string;\n delete_role_confirmation: string;\n delete_this_user: string;\n no_users_yet: string;\n add_logged_user_as_admin: string;\n add_current_user_as_admin: string;\n create_default_roles_and_add_admin: string;\n delete_user_confirmation: string;\n create_your_users_and_roles: string;\n no_users_or_roles_defined: string;\n save_before_changing_schema: string;\n edit_schema_for_this_form: string;\n no_permissions_to_edit_collection: string;\n\n // ─── Rename group dialog ──────────────────────────────────────\n rename_group: string;\n group_name_label: string;\n group_name_empty_error: string;\n group_name_exists_error: string;\n\n // ─── Search ───────────────────────────────────────────────────\n search_collections: string;\n\n // ─── Navigation groups ────────────────────────────────────────\n /** Default group name shown when collections/views have no explicit group */\n views_group: string;\n\n // ─── Entity Edit View ─────────────────────────────────────────\n youd_need_to_save_before_additional_collections: string;\n\n // ─── Not Found Page ───────────────────────────────────────────\n page_not_found: string;\n page_not_found_body: string;\n back_to_home: string;\n\n // ─── Collection Editor ─────────────────────────────────────────\n default_collection_view: string;\n table_view: string;\n cards_view: string;\n kanban_view: string;\n choose_how_entities_displayed_default: string;\n\n document_view: string;\n side_panel: string;\n full_screen: string;\n should_documents_opened_full_screen: string;\n\n select_custom_view: string;\n no_custom_views_defined: string;\n select_custom_action: string;\n no_custom_actions_defined: string;\n\n no_collections_found: string;\n start_building_collections: string;\n create_first_collection: string;\n define_collections_programmatically: string;\n\n edit_collection: string;\n no_permissions_edit_collection: string;\n no_permissions_create_collection: string;\n create_collection: string;\n update_collection: string;\n\n new_collection: string;\n add_new_collection: string;\n collection_with_name: string;\n change_icon: string;\n is_subcollection_of: string;\n name: string;\n collection_name_description: string;\n path: string;\n relative_path_to_parent: string;\n path_in_database: string;\n singular_name: string;\n singular_name_description: string;\n description: string;\n description_of_collection: string;\n collection_id: string;\n collection_id_description: string;\n collection_group: string;\n collection_group_description: string;\n advanced_settings: string;\n doc_history_global: string;\n doc_history_enabled: string;\n doc_history_not_enabled: string;\n doc_history_description: string;\n document_id_generation: string;\n code_defined: string;\n users_must_define_id: string;\n users_can_define_id: string;\n doc_id_auto_generated: string;\n config_doc_id_generation: string;\n enable_text_search: string;\n text_search_description: string;\n database_id: string;\n default_text: string;\n\n custom_actions: string;\n more_info: string;\n define_custom_actions_cli: string;\n action_defined_in_code: string;\n add_custom_entity_action: string;\n remove_this_action: string;\n remove_action_warning: string;\n\n subcollections_of: string;\n add_subcollection: string;\n custom_views: string;\n define_custom_views_cli: string;\n view_defined_in_code: string;\n add_custom_entity_view: string;\n delete_this_subcollection: string;\n remove_collection_warning: string;\n remove_this_view: string;\n remove_view_warning: string;\n\n no_collection_selected: string;\n code_for_collection: string;\n use_config_define_json: string;\n customise_collection_code: string;\n copied: string;\n\n property_cant_be_edited: string;\n property_not_editable_description: string;\n delete_this_property: string;\n delete_property_warning: string;\n error_must_specify_id: string;\n error_id_format: string;\n error_id_already_exists: string;\n error_must_specify_title: string;\n custom_or_other: string;\n select_property_widget: string;\n error_changing_data_type: string;\n required: string;\n\n enum_form_dialog: string;\n imported_data_preview: string;\n entities_with_same_id_overwritten: string;\n collection_editor: string;\n properties_in_this_group: string;\n data_property_mapping: string;\n property_edit_view: string;\n all_of_these: string;\n any_of_these: string;\n\n only_admins_edit_roles: string;\n error_user_not_found: string;\n /** Placeholder / label for the \"all roles\" filter option */\n all_roles: string;\n role: string;\n name_of_this_role: string;\n id_of_this_role: string;\n create_entities: string;\n read_entities: string;\n update_entities: string;\n delete_entities: string;\n all_collections: string;\n create_entities_in_collections: string;\n access_all_data_in_every_collection: string;\n update_data_in_any_collection: string;\n delete_data_in_any_collection: string;\n allow_all_permissions_in_this_collections: string;\n all: string;\n customise_permissions_description: string;\n create_collections: string;\n yes: string;\n no: string;\n can_user_create_collections: string;\n edit_collections: string;\n only_own_collections: string;\n own: string;\n can_user_edit_collections: string;\n delete_collections: string;\n can_user_delete_collections: string;\n error_saving_role: string;\n create_role: string;\n update: string;\n\n only_admins_change_roles: string;\n must_be_at_least_one_admin: string;\n logged_user_not_found: string;\n user: string;\n user_id: string;\n error_updating_asset: string;\n error_deleting_asset: string;\n name_of_this_user: string;\n email_of_this_user: string;\n roles: string;\n create_user: string;\n\n filters: string;\n multiple_entities: string;\n unsaved_changes: string;\n so_empty: string;\n no_results: string;\n refresh_data: string;\n dark_mode: string;\n light_mode: string;\n system_mode: string;\n ok: string;\n save_collection_config: string;\n search_for_more_icons: string;\n ai_modified: string;\n size_label: string;\n group_by: string;\n initialize_kanban_order: string;\n\n users: string;\n add_user: string;\n add_role: string;\n is_admin: string;\n default_permissions: string;\n created_on: string;\n email: string;\n id: string;\n read: string;\n\n // data import\n column_in_file: string;\n map_to_property: string;\n default_values: string;\n default_values_description: string;\n property: string;\n default_value: string;\n autogenerate_id: string;\n id_column_description: string;\n do_not_set_value: string;\n set_value_to_true: string;\n set_value_to_false: string;\n drag_and_drop_file: string;\n error_saving_data: string;\n retry: string;\n saving_data: string;\n entities_saved: string;\n do_not_close_tab: string;\n import: string;\n import_data: string;\n upload_file_description: string;\n back: string;\n next: string;\n save_data: string;\n use_column_as_id: string;\n do_not_import_property: string;\n entities_will_be_overwritten: string;\n data_imported_successfully: string;\n\n // data export\n export: string;\n export_data: string;\n download_table_csv: string;\n csv: string;\n json: string;\n dates_as_timestamps: string;\n dates_as_strings: string;\n flatten_arrays: string;\n download: string;\n large_number_of_documents: string;\n include_undefined_values: string;\n submit: string;\n\n no_filterable_properties: string;\n apply_filters: string;\n\n // ─── Filter Presets ──────────────────────────────────────────\n /** Label shown on the filter presets dropdown trigger */\n filter_presets?: string;\n /** Tooltip shown when hovering over a preset entry */\n filter_preset_apply?: string;\n /** Shown when a preset is active, with {{label}} interpolation */\n filter_preset_active?: string;\n\n list: string;\n table_view_mode: string;\n cards: string;\n board: string;\n initialize_kanban_order_desc: string;\n kanban_view_not_available: string;\n kanban_view_requires_enum: string;\n no_enum_values_configured: string;\n items_need_backfill: string;\n kanban_order_not_configured: string;\n initialize: string;\n confirm_multiple_delete: string;\n delete_entity_confirm_title: string;\n\n no_filter: string;\n is_true: string;\n is_false: string;\n error_uploading_file_size: string;\n error_uploading_file_type: string;\n drag_drop_files: string;\n drag_drop_file: string;\n\n multiple_deleted: string;\n some_entities_deleted: string;\n error_deleting_entities: string;\n deleted: string;\n\n select_reference: string;\n select_references: string;\n account_settings?: string;\n profile?: string;\n sessions?: string;\n security?: string;\n change_password?: string;\n current_password?: string;\n new_password?: string;\n confirm_password?: string;\n password_changed?: string;\n passwords_dont_match?: string;\n password_too_short?: string;\n password_change_not_available?: string;\n changing_password?: string;\n display_name?: string;\n photo_url?: string;\n save_profile?: string;\n saving?: string;\n no_active_sessions?: string;\n revoking?: string;\n revoke_all_sessions?: string;\n unknown_device?: string;\n current?: string;\n role_id: string;\n role_name: string;\n add_reference: string;\n add_reference_to: string;\n\n /** RolesView — table & permissions */\n role_deleted_successfully: string;\n error_deleting_role: string;\n collection_permissions: string;\n collection: string;\n no_collections_configured: string;\n no_security_rules_defined: string;\n no_rules: string;\n\n /** UsersView — snackbar */\n bootstrap_admin_success: string;\n failed_to_bootstrap_admin: string;\n user_deleted_successfully: string;\n error_deleting_user: string;\n user_created_successfully?: string;\n invitation_sent?: string;\n invitation_sent_title?: string;\n temporary_password?: string;\n temporary_password_description?: string;\n copy_password?: string;\n password_copied?: string;\n\n /** UsersView — pagination & search */\n search_users?: string;\n created?: string;\n actions?: string;\n no_users_found?: string;\n reset_password?: string;\n reset_password_success?: string;\n reset_password_confirmation?: string;\n error_resetting_password?: string;\n\n /** Permission-denied empty states */\n no_permission_to_view_users?: string;\n no_permission_to_view_roles?: string;\n no_permission_description?: string;\n\n /** Editor table-bubble */\n add_row_before: string;\n add_row_after: string;\n delete_row: string;\n add_column_before: string;\n add_column_after: string;\n delete_column: string;\n delete_table: string;\n\n /** Editor image-bubble */\n alt_text: string;\n title: string;\n\n /** MapFieldBinding */\n a_property_of_this_map_has_error: string;\n\n /** AI Collection Generator Popover */\n generate_collection_with_ai: string;\n modify_collection_with_ai: string;\n describe_collection_to_create: string;\n describe_changes_to_make: string;\n ai_placeholder_create: string;\n ai_placeholder_modify: string;\n ai_assist: string;\n generating: string;\n\n /** Recently extracted strings for collection editor */\n this_is_subcollection_of: string;\n use_existing_paths_database: string;\n describe_collection_ai: string;\n generate_with_ai: string;\n create_from_json_config: string;\n paste_json_config: string;\n create_collection_from_file_formats: string;\n select_template: string;\n products: string;\n collection_products_subtitle: string;\n collection_users_subtitle: string;\n blog_posts: string;\n collection_blog_posts_subtitle: string;\n pages: string;\n collection_pages_subtitle: string;\n continue_from_scratch: string;\n\n /** Admin views config */\n cms_users: string;\n roles_menu: string;\n project_settings: string;\n\n // ─── Auth ────────────────────────────────────────────────────\n by_signing_in_you_agree_to_our: string;\n terms_and_conditions: string;\n and_our: string;\n privacy_policy: string;\n email_password: string;\n sign_in_with_google: string;\n\n // --- Auth error messages ---\n auth_user_not_found: string;\n auth_wrong_password: string;\n auth_user_disabled: string;\n auth_account_exists_with_different_credential: string;\n auth_email_already_in_use: string;\n auth_google_permissions_required: string;\n auth_invalid_email_password: string;\n auth_enter_email_first: string;\n auth_password_reset_sent: string;\n auth_sign_in_account: string;\n auth_create_new_account: string;\n auth_password: string;\n auth_reset_password: string;\n auth_new_user: string;\n auth_have_account: string;\n auth_sign_in: string;\n auth_sign_up: string;\n\n auto_setup_collections_button: string;\n auto_setup_collections_title: string;\n auto_setup_collections_desc: string;\n this_can_take_a_minute: string;\n no_collections_found_to_setup: string;\n collections_have_been_setup: string;\n error_setting_up_collections: string;\n\n // --- Home ---\n add_your: string;\n database_collections: string;\n no_unmapped_collections: string;\n query_and_update_with_datatalk: string;\n\n // --- Welcome ---\n welcome_to_rebase: string;\n admin_panel_ready_bring_data: string;\n admin_panel_ready_get_started: string;\n auto_detect_collections: string;\n auto_detect_collections_desc: string;\n create_a_collection: string;\n create_collection_desc: string;\n read_the_docs: string;\n read_the_docs_desc: string;\n explore_docs: string;\n want_to_customize_with_code: string;\n to_scaffold_a_local_project: string;\n\n // ─── Collection Editor — Validation ──────────────────────────\n validation: string;\n unique: string;\n required_message: string;\n required_tooltip: string;\n unique_tooltip: string;\n lowercase: string;\n uppercase: string;\n trim: string;\n exact_length: string;\n min_length: string;\n max_length: string;\n matches_regex: string;\n not_valid_regexp: string;\n regex_helper: string;\n min_value: string;\n max_value: string;\n less_than: string;\n more_than: string;\n positive_value: string;\n negative_value: string;\n integer_value: string;\n\n // ─── Collection Editor — Property Edit ───────────────────────\n invalid_regular_expression: string;\n must_specify_target_collection: string;\n need_specify_repeat_field: string;\n need_specify_block_properties: string;\n incomplete_condition: string;\n field_name: string;\n\n // ─── Collection Editor — Display & Config ────────────────────\n kanban_column_property: string;\n select_a_property: string;\n kanban_property_not_found: string;\n no_enum_string_properties: string;\n kanban_column_description: string;\n create_property: string;\n order_property: string;\n order_property_not_found: string;\n no_number_properties: string;\n order_property_description: string;\n display_settings: string;\n default_row_size: string;\n side_dialog_width: string;\n side_dialog_width_description: string;\n inline_editing_enabled: string;\n inline_editing_disabled: string;\n inline_editing_description: string;\n include_json_view: string;\n no_json_view: string;\n json_view_description: string;\n not_found_suffix: string;\n\n // ─── Editor ─────────────────────────────────────────────────\n editor_text: string;\n editor_text_description: string;\n editor_heading_1: string;\n editor_heading_1_description: string;\n editor_heading_2: string;\n editor_heading_2_description: string;\n editor_heading_3: string;\n editor_heading_3_description: string;\n editor_todo_list: string;\n editor_todo_list_description: string;\n editor_bullet_list: string;\n editor_bullet_list_description: string;\n editor_numbered_list: string;\n editor_numbered_list_description: string;\n editor_quote: string;\n editor_quote_description: string;\n editor_code: string;\n editor_code_description: string;\n editor_image: string;\n editor_image_description: string;\n editor_multiple: string;\n editor_link: string;\n editor_save: string;\n editor_cancel: string;\n editor_remove_link: string;\n editor_paste_or_type_link: string;\n editor_open_in_new_window: string;\n editor_bold: string;\n editor_italic: string;\n editor_underline: string;\n editor_strikethrough: string;\n editor_autocomplete: string;\n editor_autocomplete_description: string;\n\n // ─── Text Search Dialog ─────────────────────────────────────\n text_search_dialog_title: string;\n text_search_local_not_recommended: string;\n text_search_local_fetch_warning: string;\n text_search_external_suggestion: string;\n text_search_local_description: string;\n text_search_own_implementation: string;\n text_search_enable_for_collection: string;\n text_search_enable_for_project: string;\n text_search_enabled_snackbar: string;\n\n // ─── Settings ────────────────────────────────────────────────\n settings_heading: string;\n settings_project_name: string;\n settings_default_language: string;\n settings_default_language_caption: string;\n settings_enable_local_text_search: string;\n settings_local_text_search_caption: string;\n settings_doc_history_all_collections: string;\n settings_doc_history_caption: string;\n settings_theme: string;\n settings_primary_color: string;\n settings_secondary_color: string;\n settings_sample_theme_components: string;\n settings_drag_drop_logo: string;\n settings_security_rules: string;\n settings_security_rules_description: string;\n settings_security_rules_add_domain: string;\n settings_security_rules_caption: string;\n\n // ─── Studio: SQL Editor ─────────────────────────────────────\n studio_sql_executing_query?: string;\n studio_sql_query_error?: string;\n studio_sql_run_query_placeholder?: string;\n studio_sql_visual_execution_plan?: string;\n studio_sql_success?: string;\n studio_sql_no_results?: string;\n studio_sql_rows?: string;\n studio_sql_time?: string;\n studio_sql_copy_markdown?: string;\n studio_sql_export_json?: string;\n studio_sql_export_csv?: string;\n studio_sql_format_sql?: string;\n studio_sql_explain?: string;\n studio_sql_limit_1000: string;\n studio_sql_remove_from_favorites?: string;\n studio_sql_add_to_favorites?: string;\n studio_sql_save?: string;\n studio_sql_run?: string;\n studio_sql_database?: string;\n studio_sql_role?: string;\n studio_sql_admin?: string;\n studio_sql_select_db?: string;\n studio_sql_query_results?: string;\n studio_sql_save_snippet?: string;\n studio_sql_snippet_name?: string;\n studio_sql_snippet_name_placeholder?: string;\n studio_sql_snippet_saved_local?: string;\n studio_sql_cancel?: string;\n studio_sql_dangerous_operation?: string;\n studio_sql_dangerous_operation_body?: string;\n studio_sql_snippet_saved?: string;\n studio_sql_markdown_copied?: string;\n studio_sql_markdown_copy_failed?: string;\n studio_sql_row_updated?: string;\n studio_sql_cannot_edit_missing_query?: string;\n studio_sql_cannot_resolve_table?: string;\n studio_sql_missing_pk?: string;\n studio_sql_update_failed?: string;\n studio_sql_execution_not_supported?: string;\n studio_sql_error_executing?: string;\n studio_sql_error_explaining?: string;\n studio_sql_save_first_to_favorite?: string;\n studio_sql_cms?: string;\n studio_sql_cms_collections_tooltip?: string;\n studio_sql_edit_entity?: string;\n studio_sql_sql_not_supported?: string;\n studio_sql_fetch_error?: string;\n studio_sql_unexpected_format?: string;\n studio_sql_no_tables?: string;\n studio_sql_schema_fetch_error?: string;\n\n // ─── Studio: SQL Editor Sidebar ──────────────────────────────\n studio_sql_sidebar_snippets?: string;\n studio_sql_sidebar_history?: string;\n studio_sql_sidebar_schema?: string;\n studio_sql_sidebar_no_snippets?: string;\n studio_sql_sidebar_save_snippet_hint?: string;\n studio_sql_sidebar_no_history?: string;\n studio_sql_sidebar_history_hint?: string;\n studio_sql_sidebar_delete_snippet?: string;\n\n // ─── Studio: Schema Browser ──────────────────────────────────\n studio_schema_tables?: string;\n studio_schema_loading?: string;\n studio_schema_no_tables?: string;\n studio_schema_retry?: string;\n studio_schema_primary_key?: string;\n studio_schema_select_all?: string;\n studio_schema_insert_into?: string;\n studio_schema_update?: string;\n studio_schema_delete_from?: string;\n studio_schema_columns?: string;\n\n // ─── Studio: RLS Editor ──────────────────────────────────────\n studio_rls_title?: string;\n studio_rls_description?: string;\n studio_rls_enabled?: string;\n studio_rls_disabled?: string;\n studio_rls_no_rls?: string;\n studio_rls_enable_rls?: string;\n studio_rls_disable_rls?: string;\n studio_rls_create_policy?: string;\n studio_rls_policies?: string;\n studio_rls_no_policies?: string;\n studio_rls_no_policies_desc?: string;\n studio_rls_add_first_policy?: string;\n studio_rls_force_rls?: string;\n studio_rls_force_rls_desc?: string;\n studio_rls_enable_force_rls?: string;\n studio_rls_disable_force_rls?: string;\n studio_rls_edit?: string;\n studio_rls_delete?: string;\n studio_rls_confirm_delete_title?: string;\n studio_rls_confirm_delete_body?: string;\n studio_rls_confirm_enable_title?: string;\n studio_rls_confirm_enable_body?: string;\n studio_rls_confirm_disable_title?: string;\n studio_rls_confirm_disable_body?: string;\n studio_rls_select_table?: string;\n studio_rls_no_tables?: string;\n studio_rls_error?: string;\n studio_rls_retry?: string;\n studio_rls_loading?: string;\n\n // ─── Studio: Policy Editor ───────────────────────────────────\n studio_policy_edit?: string;\n studio_policy_create?: string;\n studio_policy_defining_rules?: string;\n studio_policy_cancel?: string;\n studio_policy_save?: string;\n studio_policy_template?: string;\n studio_policy_select_template?: string;\n studio_policy_name?: string;\n studio_policy_name_placeholder?: string;\n studio_policy_behavior?: string;\n studio_policy_permissive?: string;\n studio_policy_permissive_desc?: string;\n studio_policy_restrictive?: string;\n studio_policy_restrictive_desc?: string;\n studio_policy_command?: string;\n studio_policy_target_roles?: string;\n studio_policy_roles_placeholder?: string;\n studio_policy_using_expr?: string;\n studio_policy_using_expr_desc?: string;\n studio_policy_check_expr?: string;\n studio_policy_check_expr_desc?: string;\n studio_policy_help_title?: string;\n studio_policy_help_intro?: string;\n studio_policy_help_step1_title: string;\n studio_policy_help_step1_desc: string;\n studio_policy_help_step2_title: string;\n studio_policy_help_step2_desc: string;\n studio_policy_help_role_public?: string;\n studio_policy_help_role_authenticated?: string;\n studio_policy_help_role_anon?: string;\n studio_policy_help_step3_title: string;\n studio_policy_help_step3_desc: string;\n studio_policy_help_step3_example: string;\n studio_policy_help_step4_title: string;\n studio_policy_help_step4_desc: string;\n studio_policy_help_step4_example: string;\n studio_policy_help_auth_vars_title?: string;\n studio_policy_help_auth_vars_desc?: string;\n studio_policy_help_auth_uid?: string;\n studio_policy_help_auth_jwt?: string;\n studio_policy_help_auth_roles?: string;\n studio_policy_help_docs_cta?: string;\n studio_policy_help_read_docs?: string;\n studio_policy_help_got_it?: string;\n\n // ─── Studio: UI Actions ──────────────────────────────────────\n studio_add_kanban_column?: string;\n studio_add_kanban_column_title?: string;\n studio_add_kanban_column_name?: string;\n studio_add_kanban_column_name_placeholder?: string;\n studio_add_kanban_column_add?: string;\n studio_add_kanban_column_cancel?: string;\n studio_collection_view_sql?: string;\n studio_collection_view_cms?: string;\n studio_editor_collection_tooltip?: string;\n studio_editor_collection_no_permission?: string;\n studio_editor_collection_start_tooltip?: string;\n studio_editor_collection_start_no_permission?: string;\n studio_editor_collection_start_copied?: string;\n studio_editor_entity_tooltip?: string;\n studio_editor_entity_no_permission?: string;\n studio_home_edit_collection?: string;\n studio_home_delete_collection?: string;\n studio_home_confirm_delete_title?: string;\n studio_home_confirm_delete_body?: string;\n studio_kanban_setup?: string;\n studio_missing_reference?: string;\n studio_missing_reference_create?: string;\n studio_new_collection?: string;\n studio_new_collection_card?: string;\n studio_new_collection_no_permission?: string;\n studio_property_add_column?: string;\n studio_property_add_column_no_permission?: string;\n studio_add_kanban_column_desc?: string;\n studio_add_kanban_column_adding?: string;\n studio_collection_view_edit?: string;\n studio_editor_collection_disabled?: string;\n studio_editor_collection_edit?: string;\n studio_editor_entity_save_first?: string;\n studio_editor_entity_edit_schema?: string;\n studio_editor_collection_start_save_filter?: string;\n studio_editor_collection_start_clear_filter?: string;\n studio_editor_collection_start_reset_filter?: string;\n studio_editor_collection_start_saved?: string;\n studio_home_duplicate_collection?: string;\n studio_home_delete?: string;\n studio_home_confirm_delete_no_data?: string;\n studio_home_collection_deleted?: string;\n studio_kanban_configure?: string;\n studio_missing_reference_error?: string;\n studio_new_collection_add?: string;\n\n // ─── Property field labels ──────────────────────────────────\n db_column_type?: string;\n primary_key_unique_id?: string;\n spread_children_as_columns?: string;\n mode?: string;\n timezone?: string;\n target_collection?: string;\n\n // ─── Storage property ───────────────────────────────────────\n storage_file_name?: string;\n storage_path?: string;\n storage_max_size?: string;\n storage_resize_mode?: string;\n storage_output_format?: string;\n storage_max_width?: string;\n storage_max_height?: string;\n storage_quality?: string;\n storage_file_upload_config?: string;\n storage_image_resize_config?: string;\n storage_all_file_types?: string;\n storage_allowed_file_types?: string;\n storage_include_bucket_url?: string;\n storage_save_url?: string;\n\n // ─── DateTime property ──────────────────────────────────────\n datetime_automatic_value?: string;\n\n // ─── Markdown property ──────────────────────────────────────\n markdown_paste_behavior?: string;\n markdown_strip_html?: string;\n markdown_convert_pasted?: string;\n}\n","import React, { PropsWithChildren } from \"react\";\n\nimport type { EntityCollection, CollectionActionsProps, EntityTableController, SelectionController } from \"./collections\";\nimport type { EntityStatus } from \"./entities\";\nimport type { InferPropertyType, Property } from \"./properties\";\nimport type { FormContext } from \"./entity_views\";\nimport type { RebaseContext } from \"../rebase_context\";\nimport type { NavigationGroupMapping, AppView } from \"../controllers/navigation\";\n\nimport type { User } from \"../users\";\nimport type { SlotContribution } from \"./slots\";\n\n/**\n * Props interface for custom field components.\n *\n * The `@rebasepro/admin` package re-exports a narrower version of this\n * interface that adds `formex` and layout-specific fields. This base\n * definition captures the core contract that every field renderer must\n * satisfy, regardless of where it is rendered.\n *\n * @typeParam P - The property type this field is bound to\n * @typeParam CustomProps - Extra props injected via the property's `customProps`\n * @typeParam M - The entity model type\n * @group Form custom fields\n */\nexport interface FieldProps<\n P extends Property = Property,\n CustomProps = unknown,\n M extends Record<string, unknown> = Record<string, unknown>\n> {\n /** Key of the property (e.g. \"user.name\" for a nested path) */\n propertyKey: string;\n\n /** Current value of this field */\n value: InferPropertyType<P> | null;\n\n /** Set value of field directly */\n setValue: (value: InferPropertyType<P> | null, shouldValidate?: boolean) => void;\n\n /** Set value of a different field directly */\n setFieldValue: (propertyKey: string, value: unknown, shouldValidate?: boolean) => void;\n\n /** Is the form currently submitting */\n isSubmitting?: boolean;\n\n /** Should this field show the error indicator */\n showError?: boolean;\n\n /** Error message for this field, or undefined if valid */\n error?: string;\n\n /** Has this field been touched */\n touched?: boolean;\n\n /** Property related to this field */\n property: P;\n\n /** Should this field include a description */\n includeDescription?: boolean;\n\n /** Flag to indicate that the underlying value has been updated in the driver */\n underlyingValueHasChanged?: boolean;\n\n /** Is this field part of an array */\n partOfArray?: boolean;\n\n /** Is this field part of a block */\n partOfBlock?: boolean;\n\n /** Display the child properties directly, without being wrapped in an extendable panel */\n minimalistView?: boolean;\n\n /** Should this field autofocus on mount */\n autoFocus?: boolean;\n\n /** Additional properties set by the developer */\n customProps?: CustomProps;\n\n /** Additional values related to the state of the form or the entity */\n context: FormContext<M>;\n\n /** Flag to indicate if this field should be disabled */\n disabled?: boolean;\n\n /** Size of the field */\n size?: \"small\" | \"medium\" | \"large\";\n\n /** Callback when internal property state changes (e.g. panel expansion) */\n onPropertyChange?: (property: Partial<Property>) => void;\n}\n\n// ── Plugin ────────────────────────────────────────────────────────────\n\n/**\n * Interface used to define plugins for Rebase.\n * Plugins contribute UI via **slots**, wrap subtrees with **providers**,\n * and inject behavioral logic via **hooks**.\n * @group Core\n */\nexport interface RebasePlugin {\n /**\n * Unique key identifying this plugin.\n */\n key: string;\n\n /**\n * If true, no CMS content is shown until this plugin finishes loading.\n */\n loading?: boolean;\n\n /**\n * UI slot contributions rendered at the matching extension points.\n */\n slots?: SlotContribution[];\n\n /**\n * HOC providers wrapping root or form content.\n * Providers with `scope: \"root\"` wrap the entire CMS below RebaseContext.\n * Providers with `scope: \"form\"` wrap each entity form/edit view.\n */\n providers?: PluginProvider[];\n\n /**\n * Behavioral hooks (non-UI) — collection modification, search blocking,\n * column reordering, navigation entries, etc.\n */\n hooks?: PluginHooks;\n\n /**\n * Field wrapping for custom field rendering (e.g. data enhancement).\n */\n fieldBuilder?: FieldBuilderConfig;\n\n /**\n * Views to be automatically added to the navigation.\n */\n views?: AppView[];\n\n\n /**\n * Optional lifecycle hooks. Called by the Rebase runtime\n * at appropriate points in the app lifecycle.\n */\n lifecycle?: PluginLifecycle;\n}\n\n// ── Provider ──────────────────────────────────────────────────────────\n\n/**\n * A HOC provider that wraps a subtree of the CMS.\n * @group Plugins\n */\nexport interface PluginProvider {\n /**\n * `\"root\"` — wraps the entire CMS below RebaseContext.\n * `\"form\"` — wraps each entity form / edit view.\n */\n scope: \"root\" | \"form\";\n\n /**\n * The provider component. Must accept `children`.\n * Typed loosely because extra props are passed via the `props` field;\n * strict signatures cause contravariance issues.\n */\n Component: React.ComponentType<PropsWithChildren<Record<string, unknown>>>;\n\n /**\n * Additional props passed to the Component.\n */\n props?: Record<string, unknown>;\n}\n\n// ── Hooks ─────────────────────────────────────────────────────────────\n\n/**\n * Behavioral hooks that a plugin can provide.\n * These are non-UI extension points for modifying CMS behavior.\n * @group Plugins\n */\nexport interface PluginHooks {\n /**\n * Modify a single collection before it is rendered (synchronous).\n */\n modifyCollection?: (collection: EntityCollection) => EntityCollection;\n\n /**\n * Async version of modifyCollection — supports fetching remote config.\n * Runs during navigation resolution. If provided alongside `modifyCollection`,\n * the sync version runs first, then the async version.\n */\n modifyCollectionAsync?: (collection: EntityCollection) => Promise<EntityCollection>;\n\n /**\n * Modify, add or remove collections.\n */\n injectCollections?: (collections: EntityCollection[]) => EntityCollection[];\n\n /**\n * Callback called when columns are reordered via drag and drop.\n */\n onColumnsReorder?: (props: {\n fullPath: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n collection: EntityCollection;\n newPropertiesOrder: string[];\n }) => void;\n\n /**\n * Callback called when Kanban board columns are reordered.\n */\n onKanbanColumnsReorder?: (props: {\n fullPath: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n collection: EntityCollection;\n kanbanColumnProperty: string;\n newColumnsOrder: string[];\n }) => void;\n\n /**\n * Navigation entries contributed by this plugin.\n */\n navigationEntries?: NavigationGroupMapping[];\n\n /**\n * Callback when navigation entry order changes (e.g. drag-and-drop).\n */\n onNavigationEntriesUpdate?: (entries: NavigationGroupMapping[]) => void;\n\n /**\n * Allow reordering collections in the home page via drag and drop.\n */\n allowDragAndDrop?: boolean;\n}\n\n// ── Plugin Lifecycle ──────────────────────────────────────────────────\n\n/**\n * Lifecycle hooks for plugins. Called by the Rebase runtime\n * at appropriate points in the app lifecycle.\n * @group Plugins\n */\nexport interface PluginLifecycle {\n /**\n * Called once when the plugin is mounted in the Rebase tree.\n * Can return a Promise for async initialization.\n */\n onMount?: (context: RebaseContext) => void | Promise<void>;\n\n /**\n * Called when the plugin is unmounted from the Rebase tree.\n * Use this for cleanup (subscriptions, timers, etc.).\n */\n onUnmount?: () => void;\n\n /**\n * Called whenever the authentication state changes.\n * Receives the new user (or null on sign-out).\n */\n onAuthStateChange?: (user: User | null) => void;\n\n /**\n * Called when a collection's visible entities change.\n * Useful for analytics, caching, or cross-plugin coordination.\n */\n onCollectionChange?: (slug: string, entities: unknown[]) => void;\n}\n\n// ── Field Builder ─────────────────────────────────────────────────────\n\n/**\n * Configuration for wrapping form field components.\n * @group Plugins\n */\nexport interface FieldBuilderConfig {\n /**\n * Returns a wrapped field component, or null to skip wrapping.\n */\n wrap: <T>(params: PluginFieldBuilderParams) => React.ComponentType<FieldProps<Property>> | null;\n\n /**\n * Optional guard — return false to skip wrapping for this field.\n */\n enabled?: (params: PluginFieldBuilderParams) => boolean;\n}\n\n// ── Prop interfaces ───────────────────────────────────────────────────\n\n/**\n * Props passed to home page collection card action components.\n * @group Models\n */\nexport interface PluginHomePageActionsProps<EP extends object = object, M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User, EC extends EntityCollection<M> = EntityCollection<M>> {\n slug: string;\n collection: EC;\n context: RebaseContext<USER>;\n}\n\n/**\n * Props passed to form action components in entity edit/form views.\n * @group Models\n */\nexport interface PluginFormActionProps<USER extends User = User, EC extends EntityCollection = EntityCollection> {\n entityId?: string | number;\n path: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n status: EntityStatus;\n collection: EC;\n disabled: boolean;\n formContext?: FormContext;\n context: RebaseContext<USER>;\n openEntityMode: \"side_panel\" | \"full_screen\" | \"split\" | \"dialog\";\n}\n\n/**\n * Parameters passed to the field builder wrap function.\n * @group Models\n */\nexport type PluginFieldBuilderParams<M extends Record<string, unknown> = Record<string, unknown>, EC extends EntityCollection<M> = EntityCollection<M>> = {\n fieldConfigId: string;\n propertyKey: string;\n property: Property;\n Field: React.ComponentType<FieldProps<Property, unknown, M>>;\n plugin: RebasePlugin;\n path?: string;\n collection?: EC;\n};\n\n/**\n * Generic props passed to plugin components that just need CMS context.\n * @group Models\n */\nexport interface PluginGenericProps<USER extends User = User> {\n context: RebaseContext<USER>;\n}\n\n/**\n * Props for additional card components in the home page.\n * @group Models\n */\nexport interface PluginHomePageAdditionalCardsProps<USER extends User = User> {\n group?: string;\n context: RebaseContext<USER>;\n}\n","import type { AuthController } from \"../controllers/auth\";\nimport type { RebaseData } from \"../controllers/data\";\nimport type { User } from \"../users\";\nimport type { EntityCollection } from \"./collections\";\nimport type { AppView } from \"../controllers/navigation\";\n\nexport type EntityCollectionsBuilder<EC extends EntityCollection = EntityCollection> = (params: {\n user: User | null,\n authController: AuthController,\n data: RebaseData\n}) => EC[] | Promise<EC[]>;\n\nexport type AppViewsBuilder = (params: {\n user: User | null,\n authController: AuthController,\n data: RebaseData\n}) => AppView[] | Promise<AppView[]>;\n","import React from \"react\";\nimport type { CollectionActionsProps, EntityTableController, SelectionController, EntityCollection } from \"./collections\";\nimport type { Entity } from \"./entities\";\nimport type { PluginFormActionProps, PluginGenericProps, PluginHomePageActionsProps, PluginHomePageAdditionalCardsProps } from \"./plugins\";\nimport type { Property } from \"./properties\";\nimport type { RebaseContext } from \"../rebase_context\";\n\n/**\n * Registry mapping slot names to their component prop types.\n * Each key represents a UI extension point in the CMS.\n * @group Plugins\n */\nexport interface SlotRegistry {\n // ── Home page ─────────────────────────────────────────────────────\n \"home.actions\": PluginGenericProps;\n \"home.cards\": PluginHomePageAdditionalCardsProps;\n \"home.children.start\": PluginGenericProps;\n \"home.children.end\": PluginGenericProps;\n /** Compact insight widget rendered inline in a home page collection card. */\n \"home.card.insight\": HomeCardInsightSlotProps;\n \"home.collection.actions\": PluginHomePageActionsProps;\n\n // ── Navigation / Drawer ───────────────────────────────────────────\n /** Rendered below the logo in the sidebar drawer. */\n \"navigation.header\": NavigationSlotProps;\n /** Rendered above the collapse toggle at the bottom of the drawer. */\n \"navigation.footer\": NavigationSlotProps;\n\n // ── Collection view ───────────────────────────────────────────────\n \"collection.actions\": CollectionActionsProps;\n \"collection.actions.start\": CollectionActionsProps;\n \"collection.header.action\": CollectionHeaderActionProps;\n \"collection.add-column\": CollectionAddColumnProps;\n \"collection.error\": CollectionErrorProps;\n /** Extra widgets rendered inside the collection toolbar row. */\n \"collection.toolbar\": CollectionToolbarProps;\n /** Custom empty-state component when a collection has no data. */\n \"collection.empty-state\": CollectionEmptyStateProps;\n /** Insight widgets rendered above the collection table. */\n \"collection.insights\": CollectionInsightsSlotProps;\n\n // ── Entity / Form ─────────────────────────────────────────────────\n \"form.actions\": PluginFormActionProps;\n \"form.actions.top\": PluginFormActionProps;\n /** Rendered before the form title / field list. */\n \"form.before\": PluginFormActionProps;\n /** Rendered after the form field list. */\n \"form.after\": PluginFormActionProps;\n\n // ── Entity row actions ────────────────────────────────────────────\n /** Per-row actions in entity tables (e.g. bulk actions, row context menus). */\n \"entity.row.actions\": EntityRowActionsProps;\n\n // ── Entity field decoration ───────────────────────────────────────\n /** Inject UI before an individual form field. */\n \"entity.field.before\": EntityFieldSlotProps;\n /** Inject UI after an individual form field. */\n \"entity.field.after\": EntityFieldSlotProps;\n\n // ── Collection filter panel ───────────────────────────────────────\n /** Custom filter sidebar for a collection. */\n \"collection.filter-panel\": CollectionFilterPanelProps;\n\n // ── Dashboard ─────────────────────────────────────────────────────\n /** Widget rendered on the dashboard / home page. */\n \"dashboard.widget\": DashboardWidgetProps;\n\n // ── Global ────────────────────────────────────────────────────────\n /** Cross-collection search bar component. */\n \"global.search\": GlobalSearchProps;\n /** Top-level toolbar actions rendered in the shell toolbar area. */\n \"shell.toolbar\": ShellToolbarProps;\n\n // ── Kanban ────────────────────────────────────────────────────────\n \"kanban.setup\": KanbanSetupProps;\n \"kanban.add-column\": KanbanAddColumnProps;\n}\n\n/**\n * Valid slot names for UI extension points.\n * @group Plugins\n */\nexport type SlotName = keyof SlotRegistry;\n\n/**\n * A single UI component contribution to a named slot.\n * @group Plugins\n */\nexport interface SlotContribution<K extends SlotName = SlotName> {\n /**\n * Which slot to contribute to.\n */\n slot: K;\n\n /**\n * The component to render in the slot.\n * Typed loosely so mixed-slot arrays work.\n * Type safety is provided at the `useSlot` call site.\n */\n Component: React.ComponentType<any>;\n\n /**\n * Additional props to merge into the slot props before rendering.\n */\n props?: Record<string, unknown>;\n\n /**\n * Ordering hint. Lower values render first. Defaults to 50.\n */\n order?: number;\n}\n\n// ── Prop interfaces for slots ─────────────────────────────────────────\n\n/**\n * Props for `navigation.header` and `navigation.footer` slots.\n * @group Plugins\n */\nexport interface NavigationSlotProps {\n drawerOpen: boolean;\n drawerHovered: boolean;\n context: RebaseContext;\n}\n\n/**\n * Props for the `collection.toolbar` slot.\n * @group Plugins\n */\nexport interface CollectionToolbarProps {\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n tableController: EntityTableController;\n selectionController: SelectionController;\n}\n\n/**\n * Props for the `collection.empty-state` slot.\n * @group Plugins\n */\nexport interface CollectionEmptyStateProps {\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n canCreate: boolean;\n onNewClick?: () => void;\n}\n\n/**\n * Props for the `collection.header.action` slot.\n * @group Plugins\n */\nexport interface CollectionHeaderActionProps {\n property: Property;\n propertyKey: string;\n path: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n onHover: boolean;\n collection: EntityCollection;\n tableController: EntityTableController;\n}\n\n/**\n * Props for the `collection.add-column` slot.\n * @group Plugins\n */\nexport interface CollectionAddColumnProps {\n path: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n collection: EntityCollection;\n tableController: EntityTableController;\n}\n\n/**\n * Props for the `collection.error` slot.\n * @group Plugins\n */\nexport interface CollectionErrorProps {\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs?: string[];\n parentEntityIds?: string[];\n error: Error;\n}\n\n/**\n * Props for the `kanban.setup` slot.\n * @group Plugins\n */\nexport interface KanbanSetupProps {\n collection: EntityCollection;\n fullPath: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n}\n\n/**\n * Props for the `kanban.add-column` slot.\n * @group Plugins\n */\nexport interface KanbanAddColumnProps {\n collection: EntityCollection;\n fullPath: string;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n columnProperty: string;\n}\n\n// ── New slot prop interfaces ──────────────────────────────────────────\n\n/**\n * Props for `entity.row.actions` slot.\n * Rendered for each row in an entity collection table.\n * @group Plugins\n */\nexport interface EntityRowActionsProps {\n entity: Entity;\n entityId: string;\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n selectionController: SelectionController;\n context: RebaseContext;\n}\n\n/**\n * Props for `entity.field.before` and `entity.field.after` slots.\n * Rendered around individual form fields in the entity edit view.\n * @group Plugins\n */\nexport interface EntityFieldSlotProps {\n propertyKey: string;\n property: Property;\n path: string;\n entityId?: string | number;\n collection: EntityCollection;\n context: RebaseContext;\n}\n\n/**\n * Props for `collection.filter-panel` slot.\n * Custom filter sidebar rendered alongside the collection table.\n * @group Plugins\n */\nexport interface CollectionFilterPanelProps {\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n tableController: EntityTableController;\n context: RebaseContext;\n}\n\n/**\n * Props for `dashboard.widget` slot.\n * Widgets rendered on the home / dashboard page.\n * @group Plugins\n */\nexport interface DashboardWidgetProps {\n context: RebaseContext;\n}\n\n/**\n * Props for `global.search` slot.\n * Cross-collection search bar rendered in the app shell.\n * @group Plugins\n */\nexport interface GlobalSearchProps {\n context: RebaseContext;\n}\n\n/**\n * Props for `shell.toolbar` slot.\n * Actions rendered in the top-level toolbar / app bar area.\n * @group Plugins\n */\nexport interface ShellToolbarProps {\n context: RebaseContext;\n}\n\n/**\n * Props for `collection.insights` slot.\n * Insight widgets rendered above the collection table.\n * @group Plugins\n */\nexport interface CollectionInsightsSlotProps {\n path: string;\n collection: EntityCollection;\n parentCollectionSlugs: string[];\n parentEntityIds: string[];\n}\n\n/**\n * Props for `home.card.insight` slot.\n * Compact insight rendered inline in a home page collection card.\n * @group Plugins\n */\nexport interface HomeCardInsightSlotProps {\n slug: string;\n collection: EntityCollection;\n context: RebaseContext;\n}\n","import React from \"react\";\nimport type { Entity } from \"./entities\";\nimport type { EntityCollection, SelectionController } from \"./collections\";\nimport type { FormContext } from \"./entity_views\";\nimport type { User } from \"../users\";\nimport type { RebaseContext } from \"../rebase_context\";\nimport type { SideEntityController } from \"../controllers/side_entity_controller\";\n\n/**\n * An entity action is a custom action that can be performed on an entity.\n * They are displayed in the entity view and in the collection view.\n */\nexport interface EntityAction<M extends Record<string, unknown> = Record<string, unknown>, USER extends User = User> {\n /**\n * Title of the action\n */\n name: string;\n\n /**\n * Key of the action. You only need to provide this if you want to\n * override the default actions, or if you are not passing the action\n * directly to the `entityActions` prop of a collection.\n * You can define your actions at the app level, in which case you\n * must provide a key.\n * The default actions are:\n * - edit\n * - delete\n * - copy\n */\n key?: string;\n\n /**\n * Icon of the action\n */\n icon?: React.ReactElement;\n\n /**\n * Callback when the action is clicked\n * @param props\n */\n onClick(props: EntityActionClickProps<M, USER>): Promise<void> | void;\n\n /**\n * Optional callback in case you want to disable the action\n * @param props\n */\n isEnabled?(props: EntityActionClickProps<M, USER>): boolean;\n\n /**\n * When true, this action is rendered inline on each row in the list view.\n * By default, entity actions only appear in the table view and entity form.\n * Use this for actions that should be easily accessible regardless of view mode.\n */\n showActionsInListView?: boolean;\n\n /**\n * Show this action collapsed in the menu of the collection view.\n * Defaults to true\n * If false, the action will be shown in the menu\n */\n collapsed?: boolean;\n\n /**\n * Show this action in the form, defaults to true\n */\n includeInForm?: boolean;\n\n}\n\nexport type EntityActionClickProps<M extends Record<string, unknown>, USER extends User = User> = {\n entity?: Entity<M>;\n context: RebaseContext<USER>;\n\n path?: string;\n collection?: EntityCollection<M>;\n\n /**\n * Optional form context, present if the action is being called from a form.\n * This allows you to access the form state and methods, including modifying the form values.\n */\n formContext?: FormContext;\n\n /**\n * Present if this actions is being called from a side dialog only\n */\n sideEntityController?: SideEntityController;\n\n /**\n * Is the action being called from the collection view or from the entity form view?\n */\n view: \"collection\" | \"form\";\n\n /**\n * If the action is rendered in the form, is it open in a side panel or full screen?\n */\n openEntityMode: \"side_panel\" | \"full_screen\" | \"split\" | \"dialog\";\n\n /**\n * Optional selection controller, present if the action is being called from a collection view\n */\n selectionController?: SelectionController;\n\n /**\n * Optional highlight function to highlight the entity in the collection view\n * @param entity\n */\n highlightEntity?: (entity: Entity<Record<string, unknown>>) => void;\n\n /**\n * Optional unhighlight function to remove the highlight from the entity in the collection view\n * @param entity\n */\n unhighlightEntity?: (entity: Entity<Record<string, unknown>>) => void;\n\n /**\n * Optional function to navigate back (e.g. when deleting an entity or navigating from a form)\n */\n navigateBack?: () => void;\n\n /**\n * Callback to be called when the collection changes, e.g. after an entity is deleted or created.\n */\n onCollectionChange?: () => void;\n\n};\n","import React from \"react\";\nimport { ArrayProperty, MapProperty, Property, StringProperty, NumberProperty, BooleanProperty, DateProperty, GeopointProperty, ReferenceProperty, RelationProperty, VectorProperty, BinaryProperty } from \"./properties\";import { BaseProperty } from \"./properties\";\n\ntype CMSBasePropertyNoName = Omit<BaseProperty, \"name\">;\n\nexport type ConfigProperty =\n | (Omit<StringProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<NumberProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<BooleanProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<DateProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<GeopointProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<ReferenceProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<RelationProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<ArrayProperty, \"name\" | \"of\" | \"oneOf\"> & {\n name?: string;\n of?: ConfigProperty | ConfigProperty[];\n oneOf?: { properties: Record<string, ConfigProperty>; typeField?: string; valueField?: string; propertiesOrder?: string[] }\n } & CMSBasePropertyNoName)\n | (Omit<MapProperty, \"name\" | \"properties\"> & {\n name?: string;\n properties?: Record<string, ConfigProperty>\n } & CMSBasePropertyNoName)\n | (Omit<VectorProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName)\n | (Omit<BinaryProperty, \"name\"> & { name?: string } & CMSBasePropertyNoName);\n\n/**\n * This is the configuration object for a property.\n * These configs are generated by default for the properties defined in your\n * collections' configuration, but you can define your own to be used.\n */\nexport type PropertyConfig = {\n\n /**\n * Key used to identify this property config.\n */\n key: PropertyConfigId | string;\n\n /**\n * Name of this field type.\n * This is not the name of the property.\n */\n name: string;\n\n /**\n * Default config for the property.\n * This property or builder will be used as the base values for the resulting property.\n * You can also use a builder function to generate the base property.\n */\n property: ConfigProperty;\n\n /**\n * Optional icon to be used in the field selector.\n * Use a 24x24 component, in order not to break the layout.\n * Any Rebase icon can be used.\n */\n Icon?: React.ComponentType;\n\n /**\n * CSS color, used only in some plugins like the field selector.\n * e.g. \"#2d7ff9\"\n */\n color?: string;\n\n /**\n * Description of this field type.\n */\n description?: string;\n\n}\n\nexport type PropertyConfigId =\n \"text_field\" |\n \"multiline\" |\n \"markdown\" |\n \"url\" |\n \"email\" |\n \"user_select\" |\n \"select\" |\n \"multi_select\" |\n \"number_input\" |\n \"number_select\" |\n \"multi_number_select\" |\n \"file_upload\" |\n \"multi_file_upload\" |\n \"group\" |\n \"key_value\" |\n \"reference\" |\n \"reference_as_string\" |\n \"multi_references\" |\n \"relation\" |\n \"switch\" |\n \"date_time\" |\n \"repeat\" |\n \"custom_array\" |\n \"block\" |\n \"vector_input\";\n","import React from \"react\";\nimport type { Entity, EntityValues } from \"./entities\";\nimport type { EntityCollection } from \"./collections\";\nimport type { FormexController } from \"./formex\";\nimport type { ComponentRef } from \"./component_ref\";\n\n/**\n * Context passed to custom fields and entity views.\n * @group Form custom fields\n */\nexport interface FormContext<M extends Record<string, unknown> = Record<string, unknown>> {\n\n /**\n * Current values of the entity\n */\n values: M;\n\n /**\n * Update the value of a field\n */\n setFieldValue: (key: string, value: unknown, shouldValidate?: boolean) => void;\n\n /**\n * Quietly persist the entity to the database without any UI feedback\n * (no validation, no snackbar, no form reset).\n * Use this for programmatic/background saves from custom views.\n */\n save: (values: M) => void;\n\n /**\n * Submit the form — validates, saves, resets the form, and shows\n * a success snackbar. This is what the Save button calls.\n * Use this from custom views when you want the full \"user saved\" experience.\n */\n submit: () => void;\n\n /**\n * Collection of the entity being modified\n */\n collection?: EntityCollection<M>;\n\n /**\n * Entity id, it can be undefined if it's a new entity\n */\n entityId?: string | number;\n\n /**\n * Path this entity is located at\n */\n path?: string;\n\n status: \"new\" | \"existing\" | \"copy\";\n\n entity?: Entity<M>;\n\n savingError?: Error;\n\n openEntityMode: \"side_panel\" | \"full_screen\" | \"split\" | \"dialog\";\n\n /**\n * The underlying formex controller that powers the form.\n */\n formex: FormexController<M>;\n\n disabled: boolean;\n\n /**\n * Whether the form context is in read-only detail view mode.\n * Custom entity views can use this to adjust their rendering.\n */\n readOnly?: boolean;\n}\n\n\nexport type EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = {\n key: string;\n name: string;\n icon?: string | React.ReactNode;\n tabComponent?: React.ReactNode;\n includeActions?: boolean | \"bottom\";\n Builder?: ComponentRef<EntityCustomViewParams<M>>;\n position?: \"start\" | \"end\";\n};\n\n/**\n * Configuration to replace the default entity form with a custom component.\n * The Builder receives the same props as entity view tabs (entity, formContext, etc.)\n * and has full control over the UI.\n *\n * The form tab still appears in the tab bar but renders your Builder\n * instead of the auto-generated field form.\n *\n * @group Models\n */\nexport type FormViewConfig<M extends Record<string, unknown> = Record<string, unknown>> = {\n /**\n * Custom component that replaces the default form.\n */\n Builder: ComponentRef<EntityCustomViewParams<M>>;\n /**\n * If true, the save/delete action bar is rendered alongside the custom view.\n * Defaults to true.\n */\n includeActions?: boolean;\n};\n\nexport interface EntityCustomViewParams<M extends Record<string, unknown> = Record<string, unknown>> {\n collection: EntityCollection<M>;\n entity?: Entity<M>;\n modifiedValues?: EntityValues<M>;\n formContext: FormContext<M>;\n parentCollectionSlugs?: string[];\n parentEntityIds?: string[];\n}\n","/**\n * Describes the capabilities and features supported by a data source (driver).\n *\n * Each driver (Postgres, Firebase, MongoDB, etc.) declares which features it\n * supports. The CMS uses this descriptor to:\n * - Show/hide editor tabs (e.g. Relations for SQL, Subcollections for Firebase)\n * - Filter the property type picker (e.g. `relation` for SQL, `reference` for Firebase)\n * - Toggle driver-specific form controls (e.g. `columnType` for SQL)\n *\n * @group Models\n */\nexport interface DataSourceCapabilities {\n /** Unique driver key (e.g. \"postgres\", \"firestore\", \"mongodb\") */\n key: string;\n\n /** Human-readable label for the UI (e.g. \"PostgreSQL\", \"Firebase / Firestore\") */\n label: string;\n\n // ── Feature flags ─────────────────────────────────────────────────\n /** Does this source support SQL-style relations (JOINs)? */\n supportsRelations: boolean;\n\n /** Does this source support nested subcollections? */\n supportsSubcollections: boolean;\n\n /** Does this source support Row Level Security policies? */\n supportsRLS: boolean;\n\n /** Does this source support document references (Firebase-style)? */\n supportsReferences: boolean;\n\n /** Does this source support SQL column type annotations? */\n supportsColumnTypes: boolean;\n\n /** Does this source support real-time listeners? */\n supportsRealtime: boolean;\n\n // ── Admin capability flags ───────────────────────────────────────\n /** Does this source support SQL admin operations (SQL editor, EXPLAIN, etc.)? */\n supportsSQLAdmin: boolean;\n\n /** Does this source support document admin operations (aggregation, stats)? */\n supportsDocumentAdmin: boolean;\n\n /** Does this source support schema admin (unmapped tables, table metadata)? */\n supportsSchemaAdmin: boolean;\n}\n\n/**\n * Subset of DataSourceCapabilities containing only feature flags.\n * Useful when you only need to check capabilities without UI metadata.\n * @group Models\n */\nexport type DataSourceFeatures = Omit<DataSourceCapabilities, \"key\" | \"label\">;\n\n// ── Built-in driver capabilities ─────────────────────────────────────\n\n/** @group Models */\nexport const POSTGRES_CAPABILITIES: DataSourceCapabilities = {\n key: \"postgres\",\n label: \"PostgreSQL\",\n supportsRelations: true,\n supportsSubcollections: false,\n supportsRLS: true,\n supportsReferences: false,\n supportsColumnTypes: true,\n supportsRealtime: true,\n supportsSQLAdmin: true,\n supportsDocumentAdmin: false,\n supportsSchemaAdmin: true\n};\n\n/** @group Models */\nexport const FIREBASE_CAPABILITIES: DataSourceCapabilities = {\n key: \"firestore\",\n label: \"Firebase / Firestore\",\n supportsRelations: false,\n supportsSubcollections: true,\n supportsRLS: false,\n supportsReferences: true,\n supportsColumnTypes: false,\n supportsRealtime: true,\n supportsSQLAdmin: false,\n supportsDocumentAdmin: false,\n supportsSchemaAdmin: false\n};\n\n/** @group Models */\nexport const MONGODB_CAPABILITIES: DataSourceCapabilities = {\n key: \"mongodb\",\n label: \"MongoDB\",\n supportsRelations: false,\n supportsSubcollections: true,\n supportsRLS: false,\n supportsReferences: true,\n supportsColumnTypes: false,\n supportsRealtime: false,\n supportsSQLAdmin: false,\n supportsDocumentAdmin: true,\n supportsSchemaAdmin: true\n};\n\n/**\n * Fallback capabilities when the driver is unknown.\n * Enables everything so nothing is hidden unexpectedly.\n * @group Models\n */\nexport const DEFAULT_CAPABILITIES: DataSourceCapabilities = {\n key: \"(default)\",\n label: \"Default\",\n supportsRelations: true,\n supportsSubcollections: true,\n supportsRLS: true,\n supportsReferences: true,\n supportsColumnTypes: true,\n supportsRealtime: true,\n supportsSQLAdmin: true,\n supportsDocumentAdmin: true,\n supportsSchemaAdmin: true\n};\n\nconst CAPABILITIES_REGISTRY: Record<string, DataSourceCapabilities> = {\n postgres: POSTGRES_CAPABILITIES,\n firestore: FIREBASE_CAPABILITIES,\n mongodb: MONGODB_CAPABILITIES,\n \"(default)\": DEFAULT_CAPABILITIES\n};\n\n/**\n * Look up capabilities for a given driver key.\n * If `driver` is undefined or not found, returns `DEFAULT_CAPABILITIES`.\n * @group Models\n */\nexport function getDataSourceCapabilities(driver?: string): DataSourceCapabilities {\n if (!driver) return POSTGRES_CAPABILITIES; // postgres is the default driver\n return CAPABILITIES_REGISTRY[driver] ?? DEFAULT_CAPABILITIES;\n}\n\n/**\n * Register custom capabilities for a third-party driver.\n * @group Models\n */\nexport function registerDataSourceCapabilities(capabilities: DataSourceCapabilities): void {\n CAPABILITIES_REGISTRY[capabilities.key] = capabilities;\n}\n","import type { RebaseClient } from \"../controllers/client\";\n\n/**\n * Cron Job type definitions for Rebase.\n *\n * These types define the shape of cron job definitions, their runtime\n * status, and execution log entries — used across server-core, client,\n * and studio packages.\n */\n\n// =============================================================================\n// CRON JOB DEFINITION (static, declared by the developer)\n// =============================================================================\n\n/**\n * A cron job definition file exports this shape as its default export.\n * See the example cron files in `app/backend/crons/` for usage.\n */\nexport interface CronJobDefinition {\n // Cron schedule expression, e.g. \"0 3 * * *\" for daily at 3 AM.\n schedule: string;\n\n /** Human-readable name shown in the Studio UI. */\n name: string;\n\n /** Optional description shown in the Studio UI. */\n description?: string;\n\n /**\n * Whether the job is enabled at startup. Defaults to `true`.\n * Can be toggled at runtime via the Admin API.\n */\n enabled?: boolean;\n\n /**\n * Maximum number of seconds the handler may run before being\n * considered timed-out. Default: 300 (5 min).\n */\n timeoutSeconds?: number;\n\n /**\n * The handler function executed on each tick.\n * Receives a context object with the data driver and logger.\n * May return arbitrary JSON-serialisable data stored in the log.\n */\n handler: (ctx: CronJobContext) => Promise<unknown> | unknown;\n}\n\n\n/**\n * Context passed to each cron handler invocation.\n */\nexport interface CronJobContext {\n /** The job's unique ID (derived from filename). */\n jobId: string;\n\n /** The current scheduled tick timestamp. */\n scheduledAt: Date;\n\n /** A simple logger scoped to this job run. */\n log: (...args: unknown[]) => void;\n\n /** The RebaseClient instance to interact with the database. */\n client: RebaseClient;\n}\n\n// =============================================================================\n// CRON JOB RUNTIME STATUS (what the API returns)\n// =============================================================================\n\nexport type CronJobRunState = \"idle\" | \"running\" | \"success\" | \"error\" | \"disabled\";\n\n/**\n * Full runtime information about a registered cron job.\n */\nexport interface CronJobStatus {\n /** Unique identifier (derived from filename, e.g. \"cleanup-sessions\"). */\n id: string;\n\n /** Human-readable name from the definition. */\n name: string;\n\n /** Description from the definition. */\n description?: string;\n\n /** The cron schedule expression. */\n schedule: string;\n\n /** Whether the job is currently enabled. */\n enabled: boolean;\n\n /** Current run state. */\n state: CronJobRunState;\n\n /** ISO timestamp of the last execution start. */\n lastRunAt?: string;\n\n /** ISO timestamp of the next scheduled execution. */\n nextRunAt?: string;\n\n /** Duration of the last run in milliseconds. */\n lastDurationMs?: number;\n\n /** Error message from the last failed run. */\n lastError?: string;\n\n /** Total number of executions since server start. */\n totalRuns: number;\n\n /** Total number of failed executions since server start. */\n totalFailures: number;\n}\n\n// =============================================================================\n// CRON JOB LOG ENTRY\n// =============================================================================\n\nexport type CronLogLevel = \"info\" | \"error\" | \"warn\";\n\n/**\n * A single execution log entry stored in the in-memory ring buffer.\n */\nexport interface CronJobLogEntry {\n /** The job ID this log belongs to. */\n jobId: string;\n\n /** ISO timestamp when execution started. */\n startedAt: string;\n\n /** ISO timestamp when execution finished. */\n finishedAt: string;\n\n /** Duration in milliseconds. */\n durationMs: number;\n\n /** Whether this run succeeded. */\n success: boolean;\n\n /** Error message if the run failed. */\n error?: string;\n\n /** Arbitrary result data returned by the handler. */\n result?: unknown;\n\n /** Captured log lines. */\n logs: string[];\n\n /** Whether this was a manual trigger. */\n manual?: boolean;\n}\n","\n/**\n * Context passed to every backend hook.\n * Provides information about the request that triggered the hook.\n * @group Backend Hooks\n */\nexport interface BackendHookContext {\n /** The currently authenticated user making the request (if any) */\n requestUser?: { userId: string; roles: string[] };\n /** The HTTP method of the request */\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n}\n\n\n/**\n * Hooks for intercepting collection entity data at the REST API boundary.\n *\n * These run **after** per-collection `EntityCallbacks` (which execute inside\n * the DataDriver) and provide a single cross-cutting interception point for\n * ALL collections flowing through the REST API.\n *\n * Every callback receives the collection `slug` so you can target specific\n * collections or apply logic globally.\n *\n * @group Backend Hooks\n */\nexport interface DataHooks {\n /**\n * Transform an entity after it's read from the database,\n * before it's returned to the client.\n *\n * Runs for both list (GET /:slug) and single (GET /:slug/:id) fetches.\n * Return the modified entity, or `null` to filter it out.\n *\n * @param slug - The collection slug (e.g. \"orders\", \"products\")\n * @param entity - The flattened entity object (id + values merged)\n * @param context - Request context (authenticated user, HTTP method)\n */\n afterRead?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): Record<string, unknown> | null | Promise<Record<string, unknown> | null>;\n\n /**\n * Transform entity values before they are written to the database.\n * Runs on POST (create) and PUT (update).\n *\n * Return the (possibly modified) values. Throw to abort the save.\n *\n * @param slug - The collection slug\n * @param values - The raw request body values\n * @param entityId - The entity ID (only present on updates)\n * @param context - Request context\n */\n beforeSave?(slug: string, values: Record<string, unknown>, entityId: string | undefined, context: BackendHookContext): Record<string, unknown> | Promise<Record<string, unknown>>;\n\n /**\n * Called after an entity is successfully saved (created or updated).\n * Useful for side-effects like syncing to external systems.\n *\n * @param slug - The collection slug\n * @param entity - The saved entity (flattened)\n * @param context - Request context\n */\n afterSave?(slug: string, entity: Record<string, unknown>, context: BackendHookContext): void | Promise<void>;\n\n /**\n * Called before an entity is deleted. Throw to prevent deletion.\n *\n * @param slug - The collection slug\n * @param entityId - The entity ID being deleted\n * @param context - Request context\n */\n beforeDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;\n\n /**\n * Called after an entity is successfully deleted.\n *\n * @param slug - The collection slug\n * @param entityId - The deleted entity ID\n * @param context - Request context\n */\n afterDelete?(slug: string, entityId: string, context: BackendHookContext): void | Promise<void>;\n}\n\n/**\n * Backend-level hooks for intercepting data at the API boundary.\n *\n * These hooks run server-side after database operations complete and before\n * API responses are sent.\n *\n * `data` hooks complement per-collection `EntityCallbacks`. Entity callbacks\n * run inside the DataDriver (close to the DB); data hooks run at the HTTP\n * boundary (close to the client). Use data hooks for cross-cutting concerns\n * like audit logging, response enrichment, or field masking.\n *\n * @example\n * ```typescript\n * const hooks: BackendHooks = {\n * data: {\n * afterRead(slug, entity, ctx) {\n * // Mask PII for non-admin users across all collections\n * if (!ctx.requestUser?.roles.includes(\"admin\") && entity.email) {\n * return { ...entity, email: \"***\" };\n * }\n * return entity;\n * }\n * }\n * };\n * ```\n *\n * @group Backend Hooks\n */\nexport interface BackendHooks {\n /** Hooks for intercepting ALL collection entity data via the REST API */\n data?: DataHooks;\n}\n","import type React from \"react\";\n\n/**\n * Internal marker for a lazily-loaded component reference.\n * Created by the Vite transform plugin when converting string paths\n * to deferred `import()` calls. Users should NOT create these manually.\n *\n * @internal\n */\nexport interface LazyComponentRef<P = unknown> {\n readonly __rebaseLazy: true;\n readonly load: () => Promise<{ default: React.ComponentType<P> }>;\n}\n\n/**\n * A reference to a React component that can be provided in three forms:\n *\n * 1. **String path** (recommended for collection configs):\n * ```ts\n * Field: \"../../frontend/src/components/MyField\"\n * ```\n * The Vite plugin transforms this into a `LazyComponentRef` at build time.\n * On the backend, the string stays inert and is never evaluated.\n *\n * 2. **Lazy import function**:\n * ```ts\n * Field: () => import(\"../../frontend/src/components/MyField\")\n * ```\n * Standard ES dynamic import. Backend never calls the function.\n *\n * 3. **Direct component reference** (use only in frontend-only code):\n * ```ts\n * Field: MyFieldComponent\n * ```\n * Importing a component at the top level will pull React into the\n * backend runtime — only safe in code that the backend never imports.\n *\n * @group Types\n */\nexport type ComponentRef<P = any> =\n | React.ComponentType<P>\n | LazyComponentRef<P>\n | (() => Promise<{ default: React.ComponentType<P> }>)\n | string;\n\n/**\n * Type guard: checks if a value is a `LazyComponentRef` produced by the\n * Vite transform plugin.\n */\nexport function isLazyComponentRef<P = unknown>(ref: unknown): ref is LazyComponentRef<P> {\n return (\n typeof ref === \"object\" &&\n ref !== null &&\n \"__rebaseLazy\" in ref &&\n (ref as Record<string, unknown>).__rebaseLazy === true\n );\n}\n","/**\n * @module AuthAdapter\n *\n * Pluggable authentication abstraction for Rebase.\n *\n * An `AuthAdapter` decouples authentication from the database layer,\n * allowing users to bring their own auth system (Clerk, Auth0, Firebase Auth,\n * custom JWT, etc.) while keeping the Rebase admin frontend fully functional.\n *\n * @example Built-in auth (default — zero config change)\n * ```ts\n * initializeRebaseBackend({\n * auth: { jwtSecret: \"...\", google: { clientId: \"...\" } },\n * database: createPostgresAdapter({ ... }),\n * });\n * ```\n *\n * @example Custom auth\n * ```ts\n * import { createCustomAuthAdapter } from \"@rebasepro/server-core\";\n *\n * initializeRebaseBackend({\n * auth: createCustomAuthAdapter({\n * verifyRequest: async (req) => { ... },\n * }),\n * database: createPostgresAdapter({ ... }),\n * });\n * ```\n *\n * @group Auth\n */\n\nimport type { Hono } from \"hono\";\n\n// ─── Authenticated User ──────────────────────────────────────────────────────\n\n/**\n * The normalized user object returned by `AuthAdapter.verifyRequest()`.\n *\n * Regardless of the auth provider, every request is resolved to this shape\n * so that downstream middleware (RLS scoping, route guards) can work uniformly.\n *\n * @group Auth\n */\nexport interface AuthenticatedUser {\n /** Unique user identifier (provider-specific). */\n uid: string;\n /** Primary email address. */\n email: string;\n /** Human-readable display name. */\n displayName?: string | null;\n /** Avatar URL. */\n photoUrl?: string | null;\n /** Role identifiers the user holds. */\n roles: string[];\n /** Whether the user has admin privileges. */\n isAdmin: boolean;\n /** Raw bearer token from the request (for forwarding). */\n rawToken?: string;\n /** Extra claims/metadata from the auth provider. */\n claims?: Record<string, unknown>;\n}\n\n// ─── Capabilities ────────────────────────────────────────────────────────────\n\n/**\n * Feature flags advertised by an auth adapter.\n *\n * The frontend reads these from `GET /api/auth/config` to dynamically\n * show/hide UI elements (login form, registration, password reset, etc.).\n *\n * @group Auth\n */\nexport interface AuthAdapterCapabilities {\n /**\n * Whether this adapter mounts its own `/auth/*` routes.\n *\n * - `true` for the built-in Rebase auth (login, register, refresh, etc.)\n * - `false` for external providers like Clerk or Auth0 that handle\n * auth flows outside of the Rebase backend.\n */\n hasBuiltInAuthRoutes: boolean;\n\n /** Supports email/password login. */\n emailPasswordLogin: boolean;\n /** Supports new user registration. */\n registration: boolean;\n /** Supports password reset flow. */\n passwordReset: boolean;\n /** Supports session listing/revocation. */\n sessionManagement: boolean;\n /** Supports profile updates (display name, photo). */\n profileUpdate: boolean;\n /** Supports email verification. */\n emailVerification: boolean;\n /** List of enabled OAuth provider IDs (e.g. `[\"google\", \"github\"]`). */\n enabledProviders: string[];\n\n /**\n * For external auth (Clerk, Auth0, etc.): the URL where the user should\n * be redirected for login. The Rebase frontend will navigate here instead\n * of showing its own login form.\n */\n externalLoginUrl?: string;\n\n /**\n * True when no users exist yet — first-user bootstrap mode.\n * Only applicable for built-in auth.\n */\n needsSetup?: boolean;\n\n /** Whether new user registration is enabled (may differ from `registration` capability at runtime). */\n registrationEnabled?: boolean;\n}\n\n// ─── User Management ────────────────────────────────────────────────────────\n\n/**\n * Options for paginated user listing.\n * @group Auth\n */\nexport interface AuthUserListOptions {\n limit?: number;\n offset?: number;\n search?: string;\n orderBy?: string;\n orderDir?: \"asc\" | \"desc\";\n roleId?: string;\n}\n\n/**\n * Paginated user listing result.\n * @group Auth\n */\nexport interface AuthUserListResult {\n users: AuthUserData[];\n total: number;\n limit: number;\n offset: number;\n}\n\n/**\n * User data exposed by the auth adapter.\n * @group Auth\n */\nexport interface AuthUserData {\n id: string;\n email: string;\n displayName?: string | null;\n photoUrl?: string | null;\n emailVerified?: boolean;\n metadata?: Record<string, unknown>;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\n/**\n * Data for creating a user.\n * @group Auth\n */\nexport interface AuthCreateUserData {\n email: string;\n password?: string;\n displayName?: string;\n photoUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * User management operations for the admin panel.\n *\n * Optional — if not provided by the adapter, the user management UI is hidden.\n *\n * @group Auth\n */\nexport interface UserManagementAdapter {\n listUsers(options?: AuthUserListOptions): Promise<AuthUserListResult>;\n getUserById(id: string): Promise<AuthUserData | null>;\n createUser(data: AuthCreateUserData): Promise<AuthUserData>;\n updateUser(id: string, data: Partial<AuthCreateUserData>): Promise<AuthUserData | null>;\n deleteUser(id: string): Promise<void>;\n getUserRoles(userId: string): Promise<string[]>;\n setUserRoles(userId: string, roleIds: string[]): Promise<void>;\n}\n\n// ─── User Creation Lifecycle ─────────────────────────────────────────────────\n\n/**\n * Result of `AuthAdapter.prepareUserCreation()`.\n *\n * Contains the processed values ready for persistence and metadata\n * needed by the finalization step.\n *\n * @group Auth\n */\nexport interface UserCreationPrepareResult {\n /** Processed values to persist (passwordHash instead of raw password, etc.). */\n values: Record<string, unknown>;\n /** Cleartext password for post-save processing (email or admin display). */\n clearPassword?: string;\n /** Whether the hook already handled the invitation (email, etc.). */\n hookHandledEmail: boolean;\n /** Whether an invitation was sent (only relevant when hookHandledEmail is true). */\n invitationSent: boolean;\n}\n\n/**\n * Result of `AuthAdapter.finalizeUserCreation()`.\n *\n * Returned to the REST API for inclusion in the response.\n *\n * @group Auth\n */\nexport interface UserCreationFinalizeResult {\n /** If set, returned to the admin in the API response. */\n temporaryPassword?: string;\n /** Whether an invitation email was sent. */\n invitationSent: boolean;\n}\n\n// ─── Auth Adapter ────────────────────────────────────────────────────────────\n\n/**\n * Pluggable authentication adapter for Rebase.\n *\n * This is the **key interface** that decouples authentication from the\n * database layer. Each auth adapter knows how to:\n *\n * 1. Verify incoming HTTP requests (`verifyRequest`)\n * 2. Optionally manage users (for the admin panel)\n * 3. Optionally mount auth-specific routes (login, register, etc.)\n * 4. Advertise its capabilities so the frontend can adapt\n *\n * The built-in Rebase auth implements this interface internally.\n * External providers (Clerk, Auth0, Firebase Auth) provide their own adapters.\n * Users with custom auth can use `createCustomAuthAdapter()` for a minimal setup.\n *\n * @group Auth\n */\nexport interface AuthAdapter {\n /**\n * Unique identifier for this auth adapter.\n *\n * @example \"rebase-builtin\", \"clerk\", \"auth0\", \"firebase\", \"custom\"\n */\n readonly id: string;\n\n // ── Request Authentication ──────────────────────────────────────────\n\n /**\n * Verify an incoming request and extract the authenticated user.\n *\n * This replaces the hardcoded JWT verification in server-core's middleware.\n * Each adapter implements its own token verification strategy:\n * - Built-in: verify Rebase JWT\n * - Clerk: call Clerk's `verifyToken()`\n * - Auth0: validate Auth0 JWT with JWKS\n * - Custom: whatever logic the user provides\n *\n * @param request - The raw `Request` object (portable across Hono, Express, Fastify)\n * @returns The authenticated user, or `null` for unauthenticated requests.\n * Throw an error to reject the request with 401.\n */\n verifyRequest(request: Request): Promise<AuthenticatedUser | null>;\n\n /**\n * Verify a raw bearer token and extract the authenticated user.\n *\n * Used for **WebSocket authentication**, where there is no HTTP `Request`\n * object — only a token string sent over the socket.\n *\n * If not implemented, the default behavior synthesizes a minimal `Request`\n * with an `Authorization: Bearer <token>` header and delegates to\n * `verifyRequest()`. Adapters should override this if their token\n * verification logic doesn't depend on request headers/cookies.\n *\n * @param token - The raw bearer token string.\n * @returns The authenticated user, or `null` if the token is invalid.\n */\n verifyToken?(token: string): Promise<AuthenticatedUser | null>;\n\n // ── User Management (for admin panel) ────────────────────────────\n\n /**\n * User CRUD for the admin panel's user management UI.\n * Optional — if not provided, user management UI is hidden.\n */\n userManagement?: UserManagementAdapter;\n\n // ── Auth Routes ─────────────────────────────────────────────────────\n\n /**\n * Mount adapter-specific auth routes (login, register, refresh, etc.).\n *\n * - Built-in adapter: mounts `/auth/login`, `/auth/register`, etc.\n * - External adapter: typically returns `undefined` (auth is handled externally).\n * - Custom adapter: user mounts their own routes.\n *\n * The return type uses `Hono<any, any, any>` because this sub-app will be\n * mounted into a parent app via `.route()`, which accepts any Hono env type.\n * Adapter implementations are free to use their own env (e.g. `Hono<HonoEnv>`).\n *\n * @returns A Hono sub-app with auth routes, or `undefined` to skip route mounting.\n */\n createAuthRoutes?(): Hono<any, any, any> | undefined;\n\n /**\n * Mount admin routes (e.g. password reset for users).\n *\n * @returns A Hono sub-app with admin routes, or `undefined` to skip.\n */\n createAdminRoutes?(): Hono<any, any, any> | undefined;\n\n // ── Feature Detection ───────────────────────────────────────────────\n\n /**\n * Advertise what this auth adapter supports.\n *\n * The frontend reads this from `GET /api/auth/config` to dynamically\n * show/hide UI elements. This is the bridge between backend capabilities\n * and the frontend's `AuthCapabilities` type.\n */\n getCapabilities(): AuthAdapterCapabilities | Promise<AuthAdapterCapabilities>;\n\n // ── Lifecycle ───────────────────────────────────────────────────────\n\n /**\n * Called during backend initialization.\n * Use for running migrations, creating tables, seeding initial data, etc.\n */\n initialize?(): Promise<void>;\n\n /**\n * Called during graceful shutdown.\n * Use for closing connections, flushing caches, etc.\n */\n destroy?(): Promise<void>;\n\n // ── Collection User Creation (for auth collections) ───────────────\n\n /**\n * Prepare values for creating a user via the auth collection's REST API.\n *\n * Called on POST to a collection with `auth: true`. Handles password\n * hashing, email normalization, and any collection/backend-level hooks.\n *\n * If not implemented, the collection saves values as-is (no password hashing).\n *\n * @param values - Raw request body from the client.\n * @param collectionAuth - The parsed `AuthCollectionConfig` from the collection (if `auth` is an object).\n * @returns Processed values ready for `driver.saveEntity()`, plus metadata for the post-save step.\n */\n prepareUserCreation?(\n values: Record<string, unknown>,\n collectionAuth?: unknown\n ): Promise<UserCreationPrepareResult>;\n\n /**\n * Finalize a user creation after the entity has been persisted.\n *\n * Handles post-save work: sending invitation emails, generating\n * password-reset tokens, or falling back to returning a temporary password.\n *\n * @param entity - The persisted entity (id + values).\n * @param clearPassword - The cleartext password from the prepare step (if any).\n * @returns Metadata for the API response (temporary password, invitation status).\n */\n finalizeUserCreation?(\n entity: { id: string; values: Record<string, unknown> },\n clearPassword?: string\n ): Promise<UserCreationFinalizeResult>;\n\n // ── Service Key (optional) ──────────────────────────────────────────\n\n /**\n * A static secret key for server-to-server / script authentication.\n *\n * When set, requests with `Authorization: Bearer <serviceKey>` bypass\n * normal token verification and are granted admin-level access.\n */\n serviceKey?: string;\n}\n\n// ─── Custom Auth Adapter Options ─────────────────────────────────────────────\n\n/**\n * Options for creating a minimal custom auth adapter via `createCustomAuthAdapter()`.\n *\n * This is the simplest way to plug an existing auth system into Rebase.\n * Only `verifyRequest` is required — everything else is optional.\n *\n * @group Auth\n */\nexport interface CustomAuthAdapterOptions {\n /**\n * Verify an incoming request and return the authenticated user.\n * This is the only required method.\n */\n verifyRequest: (request: Request) => Promise<AuthenticatedUser | null>;\n\n /**\n * Verify a raw bearer token for WebSocket authentication.\n * Optional — if omitted, a synthetic `Request` is constructed and passed\n * to `verifyRequest`.\n */\n verifyToken?: (token: string) => Promise<AuthenticatedUser | null>;\n\n /** Optional user management for the admin panel. */\n userManagement?: UserManagementAdapter;\n\n /** Static service key for server-to-server auth. */\n serviceKey?: string;\n\n /** Override default capabilities. */\n capabilities?: Partial<AuthAdapterCapabilities>;\n}\n","/**\n * @module DatabaseAdapter\n *\n * Pluggable database abstraction for Rebase.\n *\n *\n * A `DatabaseAdapter` focuses purely on data persistence and related concerns (realtime, history).\n * It does NOT handle authentication — auth is managed separately by an `AuthAdapter`.\n *\n * @example\n * ```ts\n * import { createPostgresAdapter } from \"@rebasepro/server-postgresql\";\n *\n * initializeRebaseBackend({\n * database: createPostgresAdapter({ connection: db, schema }),\n * auth: { jwtSecret: \"...\" },\n * });\n * ```\n *\n * @group Backend\n */\n\nimport type { DataDriver } from \"../controllers/data_driver\";\nimport type { EntityCollection } from \"./collections\";\nimport type {\n CollectionRegistryInterface,\n DatabaseAdmin,\n InitializedDriver,\n RealtimeProvider,\n BootstrappedAuth\n} from \"./backend\";\n\n/**\n * A `DatabaseAdapter` provides data persistence for Rebase.\n *\n * @group Backend\n */\nexport interface DatabaseAdapter {\n /**\n * Which database engine this adapter handles.\n *\n * @example \"postgres\", \"mysql\", \"mongodb\", \"sqlite\"\n */\n readonly type: string;\n\n /**\n * Create the DataDriver for CRUD operations.\n *\n * This is the only **required** method.\n *\n * @param config - Coordinator-provided config containing registered\n * collections and the collection registry.\n */\n initializeDriver(config: DatabaseAdapterInitConfig): Promise<InitializedDriver>;\n\n /**\n * Create a realtime provider for this database.\n *\n * Return `undefined` if the database does not support realtime\n * change notifications.\n */\n initializeRealtime?(driverResult: InitializedDriver): Promise<RealtimeProvider | undefined>;\n\n /**\n * Initialize auth tables / services if this driver supports them.\n */\n initializeAuth?(\n config: unknown,\n driverResult: InitializedDriver,\n ): Promise<BootstrappedAuth | undefined>;\n\n /**\n * Initialize entity history tracking.\n *\n * Return `undefined` if the database does not support history.\n */\n initializeHistory?(\n config: unknown,\n driverResult: InitializedDriver,\n ): Promise<{ historyService: unknown } | undefined>;\n\n /**\n * Initialize WebSocket server for realtime operations.\n */\n initializeWebsockets?(\n server: unknown,\n realtimeService: RealtimeProvider,\n driver: DataDriver,\n config?: unknown,\n ): Promise<void> | void;\n\n /**\n * Return admin capabilities for this database (SQL editor, schema browser, branching).\n */\n getAdmin?(driverResult: InitializedDriver): DatabaseAdmin | undefined;\n\n /**\n * Mount any database-specific HTTP routes (e.g., custom admin endpoints).\n *\n * Called after all adapters are initialized.\n */\n mountRoutes?(app: unknown, basePath: string, driverResult: InitializedDriver): void;\n\n /**\n * Graceful shutdown: close connections, release resources.\n */\n destroy?(): Promise<void>;\n}\n\n/**\n * Configuration passed by the coordinator to `DatabaseAdapter.initializeDriver()`.\n *\n * @group Backend\n */\nexport interface DatabaseAdapterInitConfig {\n /** Registered collection definitions. */\n collections: EntityCollection[];\n /** The shared collection registry to register into. */\n collectionRegistry: CollectionRegistryInterface;\n}\n","export interface BreadcrumbEntry {\n title: string;\n url: string;\n /**\n * Optional entity count for collection breadcrumbs.\n * - undefined: not applicable (e.g., entity breadcrumb, custom view)\n * - null: loading\n * - number: loaded count\n */\n count?: number | null;\n /**\n * Unique identifier for this breadcrumb (e.g., collection path).\n * Used to update count without replacing entire breadcrumb array.\n */\n id?: string;\n}\n\nexport interface BreadcrumbsController {\n breadcrumbs: BreadcrumbEntry[];\n set: (props: {\n breadcrumbs: BreadcrumbEntry[];\n }) => void;\n /**\n * Update the count for a specific breadcrumb by ID.\n */\n updateCount: (id: string, count: number | null | undefined) => void;\n}\n","import type React from \"react\";\n\n// ── Scoped component name unions ──────────────────────────────────────\n\n/**\n * Components that can only be overridden at the **app level** via the\n * `components` prop on `<Rebase>`.\n *\n * These are shell-level / global components that exist outside of any\n * specific collection context.\n *\n * @group Component Overrides\n */\nexport type AppComponentName =\n // ── Shell / Layout ──\n | \"Shell.AppBar\"\n | \"Shell.Drawer\"\n | \"Shell.DrawerNavigationItem\"\n | \"Shell.DrawerNavigationGroup\"\n\n // ── Home Page ──\n | \"HomePage\"\n | \"HomePage.CollectionCard\"\n\n // ── Auth ──\n | \"Auth.LoginView\";\n\n/**\n * Components that can be overridden at the **collection level**\n * (on an individual collection definition) or at the **app level**\n * (as a default for all collections).\n *\n * When set at the app level, these act as defaults. When set on a\n * specific collection, they override the app-level default for that\n * collection only.\n *\n * @group Component Overrides\n */\nexport type CollectionComponentName =\n // ── Collection View ──\n | \"Collection.View\"\n | \"Collection.Table\"\n | \"Collection.Card\"\n | \"Collection.EmptyState\"\n | \"Collection.Actions\"\n\n // ── Entity / Form ──\n | \"Entity.Form\"\n | \"Entity.FormActions\"\n | \"Entity.DetailView\"\n | \"Entity.SidePanel\"\n | \"Entity.Preview\"\n | \"Entity.MissingReference\";\n\n/**\n * All overridable component names across all scopes.\n * @group Component Overrides\n */\nexport type OverridableComponentName = AppComponentName | CollectionComponentName;\n\n// ── Override entry ────────────────────────────────────────────────────\n\n/**\n * A single component override entry.\n *\n * - **Eject mode** (default): Your component fully replaces the built-in one.\n * It receives the same props as the original.\n *\n * - **Wrap mode** (`wrap: true`): Your component wraps the original. The\n * built-in component is passed as `OriginalComponent` in props, so you can\n * render it inside your custom layout/logic.\n *\n * @example\n * ```tsx\n * // Eject — full replacement\n * { Component: MyCustomAppBar }\n *\n * // Wrap — augment the original\n * {\n * Component: ({ OriginalComponent, ...props }) => (\n * <div>\n * <MyBanner />\n * <OriginalComponent {...props} />\n * </div>\n * ),\n * wrap: true\n * }\n * ```\n *\n * @group Component Overrides\n */\nexport interface ComponentOverride<P = any> {\n /**\n * The replacement component. Receives the same props as the built-in\n * component it replaces.\n *\n * When `wrap` is true, an additional `OriginalComponent` prop is injected\n * containing the default component, allowing you to render it within\n * your custom wrapper.\n */\n Component: React.ComponentType<P>;\n\n /**\n * When true, the original default component is injected as the\n * `OriginalComponent` prop into your Component, enabling the\n * wrapping pattern (similar to Docusaurus's `--wrap` swizzle mode).\n *\n * When false or omitted, your component fully replaces the default\n * (similar to Docusaurus's `--eject` swizzle mode).\n *\n * @default false\n */\n wrap?: boolean;\n}\n\n// ── Override maps by scope ────────────────────────────────────────────\n\n/**\n * Collection-scoped overrides. Only collection-level components\n * can be overridden here.\n *\n * Set on a collection's `components` field to customize\n * components for that specific collection.\n *\n * @example\n * ```tsx\n * const productsCollection = {\n * name: \"Products\",\n * slug: \"products\",\n * components: {\n * \"Entity.Form\": { Component: ProductForm },\n * \"Collection.EmptyState\": { Component: ProductsEmptyState },\n * \"Collection.Card\": { Component: ProductCard },\n * }\n * };\n * ```\n *\n * @group Component Overrides\n */\nexport type CollectionComponentOverrideMap = {\n [K in CollectionComponentName]?: ComponentOverride;\n};\n\n/**\n * App-level overrides. Includes both app-only components (Shell, HomePage, Auth)\n * and collection-level components (as defaults for all collections).\n *\n * Pass this to the `components` prop on `<Rebase>`.\n *\n * Collection-level components set here act as **defaults** — they apply to all\n * collections unless a specific collection overrides them in its own\n * `components`.\n *\n * @example\n * ```tsx\n * <Rebase\n * client={client}\n * components={{\n * // App-level: only available here\n * \"Shell.AppBar\": { Component: MyAppBar },\n * \"HomePage\": { Component: MyDashboard },\n *\n * // Collection defaults: apply to ALL collections\n * \"Entity.FormActions\": {\n * Component: MyFormActions,\n * wrap: true\n * },\n * \"Collection.EmptyState\": { Component: MyEmptyState },\n * }}\n * />\n * ```\n *\n * @group Component Overrides\n */\nexport type ComponentOverrideMap = {\n [K in OverridableComponentName]?: ComponentOverride;\n};\n","export * from \"./entities\";\nexport * from \"./chips\";\n\nexport * from \"./properties\";\nexport * from \"./collections\";\nexport * from \"./relations\";\n\nexport * from \"./locales\";\nexport * from \"./entity_link_builder\";\nexport * from \"./user_management_delegate\";\nexport * from \"./entity_callbacks\";\nexport * from \"./entity_overrides\";\nexport * from \"./export_import\";\nexport * from \"./modify_collections\";\nexport * from \"./formex\";\nexport * from \"./websockets\";\nexport * from \"./backend\";\nexport * from \"./translations\";\nexport * from \"./plugins\";\nexport * from \"./builders\";\nexport * from \"./slots\";\nexport * from \"./entity_actions\";\nexport * from \"./property_config\";\nexport * from \"./entity_views\";\nexport * from \"./data_source\";\nexport * from \"./cron\";\nexport * from \"./backend_hooks\";\nexport * from \"./component_ref\";\nexport * from \"./auth_adapter\";\nexport * from \"./database_adapter\";\nexport * from \"./breadcrumbs\";\nexport * from \"./component_overrides\";\n","import type { EntityCollection } from \"../types/collections\";\nimport type { EntityReference } from \"../types/entities\";\n\n/**\n * Controller that provides access to the registered entity collections.\n * @group Models\n */\nexport type CollectionRegistryController<\n DB = Record<string, unknown>,\n EC extends EntityCollection = EntityCollection\n> = {\n\n /**\n * List of the mapped collections in the CMS.\n * Each entry relates to a collection in the root database.\n * Each of the navigation entries in this field\n * generates an entry in the main menu.\n */\n collections?: EntityCollection[];\n\n /**\n * Is the registry ready to be used\n */\n initialised: boolean;\n\n /**\n * Get the collection configuration for a given path.\n * The collection is resolved from the given path or alias.\n */\n getCollection: <K extends keyof DB>(slugOrPath: Extract<K, string>, includeUserOverride?: boolean) => EC | undefined;\n\n /**\n * Get the raw, un-normalized collection configuration.\n * This bypasses the `CollectionRegistry` normalization (such as injecting `relation` instances).\n * This is strictly for the Visual Editor to manipulate AST code without persisting runtime state.\n */\n getRawCollection: (slugOrPath: string) => EC | undefined;\n\n /**\n * Retrieve all the related parent references for a given path\n * @param path\n */\n getParentReferencesFromPath: (path: string) => EntityReference[];\n\n /**\n * Retrieve all the related parent collection ids for a given path\n * @param path\n */\n getParentCollectionSlugs: (path: string) => string[];\n getParentEntityIds: (path: string) => string[];\n\n /**\n * Resolve paths from a list of ids\n * @param ids\n */\n convertIdsToPaths: (ids: string[]) => string[];\n\n};\n","export type AnalyticsController = {\n\n /**\n * Callback used to get analytics events from the CMS\n */\n onAnalyticsEvent?: (event: AnalyticsEvent, data?: object) => void;\n\n}\n\nexport type AnalyticsEvent =\n | \"entity_click\"\n | \"entity_click_from_reference\"\n\n | \"reference_selection_clear\"\n | \"reference_selection_toggle\"\n | \"reference_selected_single\"\n | \"reference_selection_new_entity\"\n\n | \"edit_entity_clicked\"\n | \"entity_edited\"\n | \"new_entity_click\"\n | \"new_entity_saved\"\n | \"copy_entity_click\"\n | \"entity_copied\"\n\n | \"single_delete_dialog_open\"\n | \"multiple_delete_dialog_open\"\n | \"single_entity_deleted\"\n | \"multiple_entities_deleted\"\n\n | \"drawer_navigate_to_home\"\n | \"drawer_navigate_to_collection\"\n | \"drawer_navigate_to_view\"\n\n | \"home_navigate_to_collection\"\n | \"home_favorite_navigate_to_collection\"\n | \"home_navigate_to_view\"\n | \"home_navigate_to_admin_view\"\n | \"home_favorite_navigate_to_view\"\n | \"home_move_card\"\n | \"home_move_group\"\n | \"home_drop_new_group\"\n\n | \"collection_inline_editing\"\n\n | \"view_mode_changed\"\n\n | \"kanban_card_moved\"\n | \"kanban_column_reorder\"\n | \"kanban_property_changed\"\n | \"kanban_new_entity_in_column\"\n | \"kanban_backfill_order\"\n\n | \"card_view_entity_click\"\n\n | \"unmapped_event\"\n ;\n","import type { User } from \"../users\";\n\n/**\n * Capabilities advertised by an auth provider.\n * UI components use this to show/hide features dynamically\n * (e.g. password reset, registration, session management).\n * @group Hooks and utilities\n */\nexport interface AuthCapabilities {\n emailPasswordLogin?: boolean;\n googleLogin?: boolean;\n registration?: boolean;\n passwordReset?: boolean;\n sessionManagement?: boolean;\n profileUpdate?: boolean;\n emailVerification?: boolean;\n /** List of enabled OAuth provider IDs (e.g. [\"google\", \"github\", \"discord\"]) */\n enabledProviders?: string[];\n}\n\n/**\n * Controller for retrieving the logged user or performing auth related operations.\n * Note that if you are implementing your AuthController, you probably will want\n * to do it as the result of a hook.\n * @group Hooks and utilities\n */\nexport type AuthController<USER extends User = User, ExtraData = unknown> = {\n\n /**\n * The user currently logged in\n * The values can be: the user object, null if they skipped login\n */\n user: USER | null;\n\n /**\n * Initial loading flag. It is used not to display the login screen\n * when the app first loads, and it has not been checked whether the user\n * is logged in or not.\n */\n initialLoading?: boolean;\n\n /**\n * Loading flag. It is used to display a loading screen when the user is\n * logging in or out.\n */\n authLoading: boolean;\n\n /**\n * Sign out\n */\n signOut: () => Promise<void>;\n\n /**\n * Error initializing the authentication\n */\n authError?: unknown;\n\n /**\n * Error dispatched by the auth provider\n */\n authProviderError?: unknown;\n\n /**\n * You can use this method to retrieve the auth token for the current user.\n */\n getAuthToken: () => Promise<string>;\n\n /**\n * Has the user skipped the login process\n */\n loginSkipped: boolean;\n\n extra: ExtraData;\n\n setExtra: (extra: ExtraData) => void;\n\n\n setUser?(user: USER | null): void;\n\n setUserRoles?(roles: string[]): void;\n\n /**\n * Capabilities advertised by the auth provider.\n * UI components use this to feature-detect what the backend supports.\n */\n capabilities?: AuthCapabilities;\n\n};\n\n/**\n * Extended auth controller with common optional auth methods.\n * Backend implementations (Rebase backend, Firebase, Supabase, etc.)\n * extend this with their own backend-specific extras.\n * @group Hooks and utilities\n */\nexport interface AuthControllerExtended<USER extends User = User, ExtraData = unknown> extends AuthController<USER, ExtraData> {\n /** Login with email and password */\n emailPasswordLogin?(email: string, password: string): Promise<void>;\n /** Login with Google — accepts an ID token, access token, or authorization code payload */\n googleLogin?: (payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }) => Promise<void>;\n /** Generic OAuth login — works with any provider. Posts payload to /auth/{providerId}. */\n oauthLogin?: (providerId: string, payload: Record<string, unknown>) => Promise<void>;\n /** Register a new user */\n register?(email: string, password: string, displayName?: string): Promise<void>;\n /** Skip login (for anonymous access if enabled) */\n skipLogin?(): void;\n /** Request password reset email */\n forgotPassword?(email: string): Promise<void>;\n /** Reset password using a token */\n resetPassword?(token: string, password: string): Promise<void>;\n /** Change password for the authenticated user */\n changePassword?(oldPassword: string, newPassword: string): Promise<void>;\n /** Update user profile */\n updateProfile?(displayName?: string, photoURL?: string): Promise<USER>;\n}\n","import { Entity, EntityValues } from \"../types/entities\";\n\n/**\n * Parameters for querying a collection.\n * Uses PostgREST-style filter syntax for consistency between\n * the SDK (HTTP) and framework (in-process) contexts.\n *\n * @group Data\n */\n/**\n * A where-clause value for a single field.\n *\n * Supports three syntaxes:\n * 1. **Equality shorthand**: raw JS values — `null`, `\"active\"`, `42`, `true`\n * 2. **Tuple syntax**: `[operator, value]` — `[\">\", 18]`, `[\"in\", [\"a\",\"b\"]]`\n * 3. **PostgREST string**: `\"eq.published\"`, `\"gte.18\"`, `\"in.(a,b)\"`\n *\n * @group Data\n */\nexport type WhereFieldValue =\n | string\n | number\n | boolean\n | null\n | [WhereFilterOpShort, any]\n | [WhereFilterOpShort, any][];\n\nexport type WhereValue<T> = T | T[] | null;\n\nexport interface LogicalCondition {\n type: \"and\" | \"or\";\n conditions: (FilterCondition | LogicalCondition)[];\n}\n\nexport interface FilterCondition {\n column: string;\n operator: FilterOperator;\n value: unknown;\n}\n\n/** Short operator strings accepted in the tuple syntax. */\nexport type WhereFilterOpShort =\n | \"==\" | \"!=\" | \">\" | \">=\" | \"<\" | \"<=\"\n | \"eq\" | \"neq\" | \"gt\" | \"gte\" | \"lt\" | \"lte\"\n | \"in\" | \"nin\" | \"not-in\"\n | \"array-contains\" | \"array-contains-any\" | \"cs\" | \"csa\";\n\nexport interface FindParams {\n /** Maximum number of items to return (default: 20) */\n limit?: number;\n /** Number of items to skip */\n offset?: number;\n /** Page number (1-indexed), alternative to offset */\n page?: number;\n /**\n * Filter object. Supports multiple syntaxes per field:\n *\n * **Equality shorthand** — raw JS values (null, string, number, boolean):\n * ```ts\n * { company_profile_id: null }\n * { status: \"active\" }\n * { age: 18 }\n * ```\n *\n * **Tuple syntax** — `[operator, value]`:\n * ```ts\n * { age: [\">=\", 18] }\n * { role: [\"in\", [\"admin\", \"editor\"]] }\n * { deleted_at: [\"!=\", null] }\n * ```\n *\n * **PostgREST string syntax** (original format):\n * ```ts\n * { status: \"eq.published\" }\n * { age: \"gte.18\" }\n * { role: \"in.(admin,editor)\" }\n * ```\n */\n where?: Record<string, WhereFieldValue>;\n /** Logical grouping conditions (AND/OR) */\n logical?: LogicalCondition;\n /**\n * Sort order. Format: \"field:direction\".\n * @example \"created_at:desc\", \"name:asc\"\n */\n orderBy?: string;\n /** Relations to include in the response */\n include?: string[];\n /** Full-text search string */\n searchString?: string;\n}\n\n/**\n * Paginated response from a collection query.\n * @group Data\n */\nexport interface FindResponse<M extends Record<string, unknown> = Record<string, unknown>> {\n /** Array of entities matching the query */\n data: Entity<M>[];\n /** Pagination metadata */\n meta: {\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n };\n}\n\nexport type FilterOperator = WhereFilterOpShort;\n\n/**\n * Fluent Query Builder Interface supported on both client and server accessors.\n * @group Data\n */\nexport interface QueryBuilderInterface<M extends Record<string, unknown> = Record<string, unknown>> {\n where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n orderBy(column: keyof M & string, ascending?: \"asc\" | \"desc\"): this;\n limit(count: number): this;\n offset(count: number): this;\n search(searchString: string): this;\n include(...relations: string[]): this;\n find(): Promise<FindResponse<M>>;\n listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;\n}\n\n/**\n * A single collection's CRUD accessor.\n *\n * This is the unified API surface used in both:\n * - The generated SDK (`client.data.products.create(...)`)\n * - Framework callbacks (`context.data.products.create(...)`)\n *\n * @group Data\n */\nexport interface CollectionAccessor<M extends Record<string, unknown> = Record<string, unknown>> {\n /**\n * Find multiple records with optional filtering, pagination, and sorting.\n */\n find(params?: FindParams): Promise<FindResponse<M>>;\n\n /**\n * Find a single record by its ID.\n */\n findById(id: string | number): Promise<Entity<M> | undefined>;\n\n /**\n * Create a new record.\n * @param data The entity data to create.\n * @param id Optional specific ID to use for the new record.\n * @returns The created entity\n */\n create(data: Partial<EntityValues<M>>, id?: string | number): Promise<Entity<M>>;\n\n /**\n * Update an existing record by ID.\n * @returns The updated entity\n */\n update(id: string | number, data: Partial<EntityValues<M>>): Promise<Entity<M>>;\n\n /**\n * Delete a record by ID.\n */\n delete(id: string | number): Promise<void>;\n\n /**\n * Delete all records in this collection.\n */\n deleteAll?(): Promise<void>;\n\n /**\n * Subscribe to a collection for real-time updates.\n * Optional method, may not be supported by all implementations (like stateless HTTP clients).\n */\n listen?(params: FindParams | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;\n\n /**\n * Subscribe to a single record for real-time updates.\n * Optional method.\n */\n listenById?(id: string | number, onUpdate: (entity: Entity<M> | undefined) => void, onError?: (error: Error) => void): () => void;\n\n /**\n * Count the number of records matching the given filter.\n */\n count?(params?: FindParams): Promise<number>;\n\n // Fluent Query Builder\n where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): QueryBuilderInterface<M>;\n where(logicalCondition: LogicalCondition): QueryBuilderInterface<M>;\n orderBy(column: keyof M & string, ascending?: \"asc\" | \"desc\"): QueryBuilderInterface<M>;\n limit(count: number): QueryBuilderInterface<M>;\n offset(count: number): QueryBuilderInterface<M>;\n search(searchString: string): QueryBuilderInterface<M>;\n include(...relations: string[]): QueryBuilderInterface<M>;\n}\n\n/**\n * The unified data access object.\n *\n * Access collections as dynamic properties: `data.products.find(...)`.\n * In the SDK this is backed by HTTP transport (typed, generated per-project).\n * In the framework this is backed by a Proxy + in-process database driver (dynamic).\n *\n * @example\n * // SDK\n * const client = createRebaseClient({ baseUrl: \"...\" });\n * await client.data.products.create({ name: \"Camera\", price: 299 });\n *\n * // Framework callback\n * callbacks: {\n * afterSave({ context }) {\n * await context.data.logs.create({ action: \"saved\", timestamp: new Date() });\n * }\n * }\n *\n * @group Data\n */\nexport interface RebaseData {\n /**\n * Get a collection accessor by slug.\n * Alternative to dynamic property access for cases where\n * the collection name is a variable.\n *\n * @example\n * const accessor = data.collection(\"products\");\n * await accessor.find({ limit: 10 });\n */\n collection(slug: string): CollectionAccessor;\n\n /**\n * Dynamic collection accessor.\n * Access any collection by its slug as a property.\n *\n * @example\n * data.products.find({ where: { status: \"eq.published\" } })\n */\n [collectionSlug: string]: CollectionAccessor | ((slug: string) => CollectionAccessor);\n}\n","/**\n * @module database_admin\n *\n * Re-exports the capability-specific admin interfaces from `@rebasepro/types/backend`.\n * This file is kept for backwards compatibility — new code should import from\n * `@rebasepro/types` directly.\n *\n * @group Admin\n */\nexport type {\n SQLAdmin,\n DocumentAdmin,\n SchemaAdmin,\n DatabaseAdmin,\n HealthCheckResult\n} from \"../types/backend\";\n\nexport {\n isSQLAdmin,\n isDocumentAdmin,\n isSchemaAdmin\n} from \"../types/backend\";\n","import type { CollectionRegistryController } from \"./collection_registry\";\nimport type { Entity, EntityStatus, EntityValues } from \"../types/entities\";\nimport type { EntityCollection, FilterValues } from \"../types/collections\";\nimport type { RebaseContext } from \"../rebase_context\";\n\n\n/**\n * @internal\n */\nexport interface FetchEntityProps<M extends Record<string, unknown> = Record<string, unknown>> {\n path: string;\n entityId: string | number;\n databaseId?: string;\n collection?: EntityCollection<M>\n}\n\n/**\n * @internal\n */\nexport type ListenEntityProps<M extends Record<string, unknown> = Record<string, unknown>> =\n FetchEntityProps<M>\n & {\n onUpdate: (entity: Entity<M> | null) => void,\n onError?: (error: Error) => void,\n }\n\n/**\n * Configuration for vector similarity search queries.\n * Vector search applies an ORDER BY distance expression and optionally\n * filters results by a distance threshold.\n */\nexport interface VectorSearchParams {\n /** Property name containing the vector column */\n property: string;\n /** Query vector to compare against */\n vector: number[];\n /** Distance function (default: \"cosine\") */\n distance?: \"cosine\" | \"l2\" | \"inner_product\";\n /** Only return results within this distance threshold */\n threshold?: number;\n}\n\n/**\n * @internal\n */\nexport interface FetchCollectionProps<M extends Record<string, unknown> = Record<string, unknown>> {\n path: string;\n collection?: EntityCollection<M>;\n filter?: FilterValues<Extract<keyof M, string>>,\n limit?: number;\n offset?: number;\n startAfter?: unknown;\n orderBy?: string;\n searchString?: string;\n order?: \"desc\" | \"asc\";\n /** Vector similarity search configuration */\n vectorSearch?: VectorSearchParams;\n}\n\n/**\n * @internal\n */\nexport type ListenCollectionProps<M extends Record<string, unknown> = Record<string, unknown>> =\n FetchCollectionProps<M> &\n {\n onUpdate: (entities: Entity<M>[]) => void;\n onError?: (error: Error) => void;\n };\n\n/**\n * @internal\n */\nexport interface SaveEntityProps<M extends Record<string, unknown> = Record<string, unknown>> {\n path: string;\n values: Partial<EntityValues<M>>;\n entityId?: string | number; // can be empty for new entities\n previousValues?: Partial<EntityValues<M>>;\n collection?: EntityCollection<M>;\n status: EntityStatus;\n}\n\n/**\n * @internal\n */\nexport interface DeleteEntityProps<M extends Record<string, unknown> = Record<string, unknown>> {\n entity: Entity<M>;\n collection?: EntityCollection<M>;\n}\n\nexport type FilterCombinationValidProps = {\n path: string;\n databaseId?: string;\n collection: EntityCollection;\n filterValues: FilterValues<string>;\n sortBy?: [string, \"asc\" | \"desc\"];\n};\n\n/**\n * Internal driver interface for communicating with the data layer.\n * This is NOT the public API — use `RebaseData` / `context.data` instead.\n * @internal\n */\nexport interface DataDriver {\n\n /**\n * Key that identifies this driver\n */\n key?: string;\n\n /**\n * If the driver has been initialised\n */\n initialised?: boolean;\n\n /**\n * Fetch data from a collection\n * @param props\n * @return Promise of entities\n */\n fetchCollection<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]>;\n\n /**\n * Listen to a collection in a given path. If you don't implement this method\n * `fetchCollection` will be used instead, with no real time updates.\n * @param props\n * @return Function to cancel subscription\n */\n listenCollection?<M extends Record<string, unknown> = Record<string, unknown>>(props: ListenCollectionProps<M>): () => void;\n\n /**\n * Retrieve an entity given a path and a collection\n * @param props\n */\n fetchEntity<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchEntityProps<M>): Promise<Entity<M> | undefined>;\n\n /**\n * Get realtime updates on one entity.\n * @param props\n * @return Function to cancel subscription\n */\n listenEntity?<M extends Record<string, unknown> = Record<string, unknown>>(props: ListenEntityProps<M>): () => void;\n\n /**\n * Save entity to the specified path\n * @param props\n */\n saveEntity<M extends Record<string, unknown> = Record<string, unknown>>(props: SaveEntityProps<M>): Promise<Entity<M>>;\n\n /**\n * Delete an entity\n * @param props\n * @return was the whole deletion flow successful\n */\n deleteEntity<M extends Record<string, unknown> = Record<string, unknown>>(props: DeleteEntityProps<M>): Promise<void>;\n\n /**\n * Delete all entities from a collection.\n * @param path Collection path\n */\n deleteAll?(path: string): Promise<void>;\n\n /**\n * Check if the given property is unique in the given collection\n * @param path Collection path\n * @param name of the property\n * @param value\n * @param entityId\n * @param collection\n * @return `true` if there are no other fields besides the given entity\n */\n checkUniqueField(\n path: string,\n name: string,\n value: unknown,\n entityId?: string | number,\n collection?: EntityCollection\n ): Promise<boolean>;\n\n /**\n * Count the number of entities in a collection\n */\n countEntities?<M extends Record<string, unknown> = Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number>;\n\n /**\n * Check if the given filter combination is valid\n * @param props\n */\n isFilterCombinationValid?(props: Omit<FilterCombinationValidProps, \"collection\"> & {\n databaseId?: string\n }): boolean;\n\n /**\n * Get the object to generate the current time in the driver\n */\n currentTime?: () => unknown;\n\n delegateToCMSModel?: (data: unknown) => unknown;\n\n cmsToDelegateModel?: (data: unknown) => unknown;\n\n initTextSearch?: (props: {\n context: RebaseContext,\n path: string,\n databaseId?: string,\n collection: EntityCollection,\n parentCollectionSlugs?: string[];\n parentEntityIds?: string[];\n }) => Promise<boolean>;\n\n /**\n * Flag to indicate if the driver has requested the initialization of the text search index\n */\n needsInitTextSearch?: boolean;\n\n // ── REST fetch capabilities ─────────────────────────────────────────\n\n /**\n * Optional REST-optimised fetch service. When present, the REST API\n * generator uses these methods instead of the generic `fetchEntity` /\n * `fetchCollection` pipeline, enabling include-aware eager-loading.\n */\n restFetchService?: RestFetchService;\n\n // ── Admin capabilities ─────────────────────────────────────────────\n //\n // Admin operations are now modelled as capability-specific interfaces\n // (SQLAdmin, DocumentAdmin, SchemaAdmin) in `@rebasepro/types/backend`.\n //\n // Drivers that support admin features should expose them here.\n // Consumers should use the `isSQLAdmin()`, `isSchemaAdmin()` etc.\n // type guards to safely narrow the type before calling methods.\n\n /**\n * Return the admin capabilities of this driver.\n * @see SQLAdmin\n * @see DocumentAdmin\n * @see SchemaAdmin\n */\n admin?: import(\"../types/backend\").DatabaseAdmin;\n\n}\n\n/**\n * REST-optimised fetch service exposed by drivers that support\n * eager-loading of relations via `include`.\n *\n * The methods return flattened rows (`{ id, ...columns }`) rather\n * than the `Entity<M>` wrapper used by the generic DataDriver API.\n *\n * @group DataDriver\n */\nexport interface RestFetchService {\n /**\n * Fetch a collection of flattened entities with optional relation includes.\n */\n fetchCollectionForRest(\n collectionPath: string,\n options?: {\n filter?: FilterValues<string>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n vectorSearch?: VectorSearchParams;\n },\n include?: string[]\n ): Promise<Record<string, unknown>[]>;\n\n /**\n * Fetch a single flattened entity with optional relation includes.\n */\n fetchEntityForRest(\n collectionPath: string,\n entityId: string | number,\n include?: string[],\n databaseId?: string\n ): Promise<Record<string, unknown> | null>;\n}\n","import type { EntityCollection } from \"../types/collections\";\n\n/**\n * @group Models\n */\nexport type PartialEntityCollection<M extends Record<string, unknown> = Record<string, unknown>> = Partial<EntityCollection<M>>;\n\n/**\n * This interface is in charge of defining the controller that persists\n * modifications to a collection or collection, and retrieves them back from\n * a data source, such as local storage or Firestore.\n */\nexport interface UserConfigurationPersistence {\n onCollectionModified: <M extends Record<string, unknown> = Record<string, unknown>>(path: string, partialCollection: PartialEntityCollection<M>) => void;\n getCollectionConfig: <M extends Record<string, unknown> = Record<string, unknown>>(path: string) => PartialEntityCollection<M>;\n recentlyVisitedPaths: string[];\n setRecentlyVisitedPaths: (paths: string[]) => void;\n favouritePaths: string[];\n setFavouritePaths: (paths: string[]) => void;\n collapsedGroups: string[];\n setCollapsedGroups: (paths: string[]) => void;\n}\n","import React from \"react\";\nimport type { EntityReference } from \"../types/entities\";\nimport type { EntityCollection } from \"../types/collections\";\nimport type { RebasePlugin } from \"../types/plugins\";\n\n/**\n * Controller that handles URL path building and resolution.\n * @group Models\n */\nexport type UrlController = {\n /**\n * Default path under the navigation routes of the CMS will be created.\n * Defaults to '/'. You may want to change this `basepath` to 'admin' for example.\n */\n basePath: string;\n\n /**\n * Default path under the collection routes of the CMS will be created.\n * It defaults to '/c'\n */\n baseCollectionPath: string;\n\n /**\n * Convert a URL path to a collection or entity path\n * `/c/products` => `products`\n * `/my_cms/c/products/B34SAP8Z` => `products/B34SAP8Z`\n * `/my_cms/my_view` => `my_view`\n * @param cmsPath\n */\n urlPathToDataPath: (cmsPath: string) => string;\n\n /**\n * Base url path for the home screen\n */\n homeUrl: string;\n\n /**\n * Check if a url path belongs to a collection\n * @param path\n */\n isUrlCollectionPath: (urlPath: string) => boolean;\n\n /**\n * Build a URL collection path from a data path\n * `products` => `/c/products`\n * `products/B34SAP8Z` => `/c/products/B34SAP8Z`\n * @param path\n */\n buildUrlCollectionPath: (path: string) => string;\n\n /**\n * Build a URL path for the CMS (e.g. for custom views)\n * @param path\n */\n buildAppUrlPath: (path: string) => string;\n\n /**\n * Turn a path with collection ids into a resolved path.\n * The ids (typically used in urls) will be replaced with relative paths (typically used in database paths)\n * @param path\n */\n resolveDatabasePathsFrom: (path: string) => string;\n\n /**\n * A function to navigate to a specified route or URL.\n *\n * @param {string} to - The target route or URL to navigate to.\n * @param {NavigateOptions} [options] - Optional configuration settings for navigation, such as replace behavior or state data.\n */\n navigate: (to: string, options?: NavigateOptions) => void;\n};\n\n/**\n * Controller that manages the state of the navigation menu,\n * including resolved views and top-level grouping.\n * @group Models\n */\nexport type NavigationStateController = {\n /**\n * Custom additional views created by the developer, added to the main\n * navigation\n */\n views?: AppView[];\n\n /**\n * Custom additional views created by the developer, added to the admin\n * navigation\n */\n adminViews?: AppView[];\n\n /**\n * Configuration for the views that should be displayed at the top\n * level of the navigation (e.g. in the home page or the navigation\n * drawer)\n */\n topLevelNavigation?: NavigationResult;\n\n /**\n * Is the navigation loading (the configuration persistence has not\n * loaded yet, or a specified navigation builder has not completed)\n */\n loading: boolean;\n\n /**\n * Was there an error while loading the navigation data\n */\n navigationLoadingError?: unknown;\n\n /**\n * Call this method to recalculate the navigation\n */\n refreshNavigation: () => void;\n\n /**\n * Plugin system allowing to extend the CMS functionality.\n */\n plugins?: RebasePlugin[];\n};\n\nexport interface NavigateOptions {\n replace?: boolean;\n state?: unknown;\n preventScrollReset?: boolean;\n relative?: \"route\" | \"path\";\n flushSync?: boolean;\n viewTransition?: boolean;\n}\n\n// currently not used, in favor of a single blocker in `RebaseRoute`\nexport type NavigationBlocker = {\n updateBlockListener: (path: string, block: boolean, basePath?: string) => () => void;\n isBlocked: (path: string) => boolean;\n proceed?: () => void;\n reset?: () => void;\n};\n\n/**\n * Custom additional views created by the developer, added to the main\n * navigation.\n * @group Models\n */\nexport interface AppView {\n\n /**\n * CMS Path you can reach this view from.\n */\n slug: string;\n\n /**\n * Name of this view\n */\n name: string;\n\n /**\n * Optional description of this view. You can use Markdown\n */\n description?: string;\n\n /**\n * Icon key to use in this view.\n * You can use any of the icons in the Lucide specs:\n * https://lucide.dev/icons/\n * e.g. 'ShoppingCart' or 'User'\n * Find all the icons in https://rebase.pro/docs/icons\n */\n icon?: string | React.ReactNode;\n\n /**\n * Should this view be hidden from the main navigation panel.\n * It will still be accessible if you reach the specified path\n */\n hideFromNavigation?: boolean;\n\n /**\n * Navigation group for this view.\n * Views sharing the same group name will be visually grouped\n * together in the drawer and home page. If not set, the view\n * falls into the default \"Views\" group.\n */\n group?: string;\n\n /**\n * Component to be rendered. This can be any React component, and can use\n * any of the provided hooks\n */\n view: React.ReactNode;\n\n /**\n * If true, a wildcard route (slug/*) is automatically registered\n * alongside the base route, enabling nested navigation within this view.\n */\n nestedRoutes?: boolean;\n\n}\n\n/**\n * A composable section that can be rendered on the home page.\n * Use this to add custom content alongside the auto-generated\n * navigation groups.\n * @group Models\n */\nexport interface HomePageSection {\n /**\n * Unique key for this section.\n */\n key: string;\n\n /**\n * Title displayed as the section header.\n */\n title: string;\n\n /**\n * Arbitrary React content rendered inside the section.\n */\n children: React.ReactNode;\n}\n\n/**\n * Used to group navigation entries in the main navigation.\n */\nexport interface NavigationGroupMapping {\n /**\n * Name of the group, used to display the group header in the UI\n */\n name: string;\n /**\n * List of collection ids or view paths that belong to this group.\n */\n entries: string[];\n /**\n * Configure which groups start collapsed.\n * Set to `true` to collapse in both drawer and home page,\n * or use an object to control each independently.\n *\n * @defaultValue false (expanded)\n */\n collapsedByDefault?: boolean | {\n drawer?: boolean;\n home?: boolean;\n };\n}\n\nexport interface NavigationEntry {\n id: string;\n url: string;\n name: string;\n slug: string;\n type: \"collection\" | \"view\" | \"admin\";\n collection?: EntityCollection;\n view?: AppView;\n description?: string;\n group: string;\n}\n\nexport type NavigationResult = {\n\n allowDragAndDrop: boolean;\n\n navigationEntries: NavigationEntry[],\n\n groups: string[],\n\n onNavigationEntriesUpdate: (entries: NavigationGroupMapping[]) => void;\n};\n\n","export interface EffectiveRoleController {\n effectiveRole: string | null;\n setEffectiveRole: (role: string | null) => void;\n}\n","/**\n * @group Models\n */\nexport interface UploadFileProps {\n file: File,\n key: string,\n metadata?: Record<string, unknown>,\n bucket?: string\n}\n\n/**\n * @group Models\n */\nexport interface UploadFileResult {\n /**\n * Storage key including the file name where the file was uploaded.\n */\n key: string;\n /**\n * Bucket where the file was uploaded\n */\n bucket: string;\n\n /**\n * Fully qualified storage URL for the uploaded file.\n *\n * For example: `s3://my-bucket/path/to/file.png`.\n *\n * This is optional for backwards compatibility.\n */\n storageUrl?: string;\n}\n\n/**\n * @group Models\n */\nexport interface DownloadConfig {\n /**\n * Temporal url that can be used to download the file\n */\n url: string | null;\n\n metadata?: DownloadMetadata;\n\n fileNotFound?: boolean;\n}\n\n/**\n * The full set of object metadata, including read-only properties.\n * @public\n */\nexport declare interface DownloadMetadata {\n /**\n * The bucket this object is contained in.\n */\n bucket: string;\n /**\n * The full path of this object.\n */\n fullPath: string;\n /**\n * The short name of this object, which is the last component of the full path.\n * For example, if path is 'full/path/image.png', name is 'image.png'.\n */\n name: string;\n /**\n * The size of this object, in bytes.\n */\n size: number;\n /**\n * Type of the uploaded file\n * e.g. \"image/jpeg\"\n */\n contentType: string;\n\n customMetadata: Record<string, unknown>;\n}\n\n/**\n * @group Models\n */\nexport interface StorageSource {\n /**\n * Upload an object, specifying a key\n * @param file\n * @param key\n * @param metadata\n * @param bucket\n */\n putObject: ({\n file,\n key,\n metadata,\n bucket\n }: UploadFileProps) => Promise<UploadFileResult>;\n\n /**\n * Convert a storage key or URL into a download configuration (signed URL equivalent)\n * @param keyOrUrl\n * @param bucket\n */\n getSignedUrl: (keyOrUrl: string, bucket?: string) => Promise<DownloadConfig>;\n\n /**\n * Get an object from a storage key.\n * It returns null if the object does not exist.\n * @param key\n * @param bucket\n */\n getObject: (key: string, bucket?: string) => Promise<File | null>;\n\n /**\n * Delete an object.\n * @param key\n * @param bucket\n */\n deleteObject: (key: string, bucket?: string) => Promise<void>;\n\n /**\n * List the contents of a prefix.\n * @param prefix\n * @param options\n */\n listObjects: (prefix: string, options?: {\n bucket?: string,\n maxResults?: number,\n pageToken?: string\n }) => Promise<StorageListResult>;\n\n}\n\n/**\n * Result returned by list().\n * @public\n */\nexport declare interface StorageListResult {\n /**\n * References to prefixes (sub-folders). You can call list() on them to\n * get its contents.\n *\n * Folders are implicit based on '/' in the object paths.\n * For example, if a bucket has two objects '/a/b/1' and '/a/b/2', list('/a')\n * will return '/a/b' as a prefix.\n */\n prefixes: StorageReference[];\n /**\n * Objects in this directory.\n * You can call getMetadata() and getDownloadUrl() on them.\n */\n items: StorageReference[];\n /**\n * If set, there might be more results for this list. Use this token to resume the list.\n */\n nextPageToken?: string;\n}\n\n/**\n * Represents a reference to an S3-compatible storage object. Developers can\n * upload, download, and delete objects, as well as get/set object metadata.\n * @public\n */\nexport declare interface StorageReference {\n /**\n * Returns a s3:// URL for this object in the form\n * `s3://<bucket>/<path>/<to>/<object>`\n * @returns The s3:// URL.\n */\n toString(): string;\n\n /**\n * A reference to the root of this object's bucket.\n */\n root: StorageReference;\n /**\n * The name of the bucket containing this reference's object.\n */\n bucket: string;\n /**\n * The full path of this object.\n */\n fullPath: string;\n /**\n * The short name of this object, which is the last component of the full path.\n * For example, if path is 'full/path/image.png', name is 'image.png'.\n */\n name: string;\n\n /**\n * A reference pointing to the parent location of this reference, or null if\n * this reference is the root.\n */\n parent: StorageReference | null;\n}\n","/**\n * Email service types — portable interface shared by RebaseClient and server-core.\n *\n * The concrete SMTP implementation lives in `@rebasepro/server-core/email`.\n * This file provides only the consumer-facing contract so that it can be\n * referenced from `RebaseClient` without dragging in nodemailer.\n */\n\n/**\n * Options for sending an email via the Rebase email service.\n */\nexport interface EmailSendOptions {\n /** Recipient email address(es). */\n to: string | string[];\n /** Email subject line. */\n subject: string;\n /** HTML body content. */\n html: string;\n /** Optional plain-text fallback. */\n text?: string;\n /** Optional reply-to address. */\n replyTo?: string;\n}\n\n/**\n * Abstraction over an email delivery backend.\n *\n * Implementations may use SMTP, AWS SES, Resend, Postmark, or any other\n * provider — consumers only interact through this interface.\n */\nexport interface EmailService {\n /** Send a single email. */\n send(options: EmailSendOptions): Promise<void>;\n /** Returns `true` when the service has valid credentials / is ready to send. */\n isConfigured(): boolean;\n /** Verify connection/credentials with the email provider. */\n verifyConnection?(): Promise<boolean>;\n}\n","import type { User } from \"../users\";\nimport type { RebaseData } from \"./data\";\nimport type { EmailService } from \"./email\";\nimport type { StorageSource } from \"./storage\";\nimport type { CronJobStatus, CronJobLogEntry } from \"../types/cron\";\n\n/**\n * Event type for authentication state changes\n */\nexport type AuthChangeEvent = \"SIGNED_IN\" | \"SIGNED_OUT\" | \"TOKEN_REFRESHED\" | \"USER_UPDATED\";\n\n/**\n * Standard session interface representing an authenticated state\n */\nexport interface RebaseSession {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n user: User;\n}\n\n/**\n * Unified Authentication Client Interface\n * Pure functional SDK interface, decoupled from UI and React hooks\n */\nexport interface AuthClient {\n /**\n * Get the current user from the server or cache\n */\n getUser(): Promise<User | null>;\n\n /**\n * Get the currently active session\n */\n getSession(): RebaseSession | null;\n\n /**\n * Sign out the current user and clear local session\n */\n signOut(): Promise<void>;\n\n /**\n * Subscribe to authentication state changes\n */\n onAuthStateChange(callback: (event: AuthChangeEvent, session: RebaseSession | null) => void): () => void;\n\n /**\n * Manually refresh the session token\n */\n refreshSession(): Promise<RebaseSession>;\n}\n\n// ─── Admin API ───────────────────────────────────────────────────────────────\n\n/**\n * User record as returned by the Admin API.\n * @group Admin\n */\nexport interface AdminUser {\n uid: string;\n email: string;\n displayName: string | null;\n photoURL: string | null;\n provider: string;\n roles: string[];\n metadata?: Record<string, any>;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Client-side Admin API interface.\n * Provides user management operations.\n * @group Admin\n */\nexport interface AdminAPI {\n listUsers(): Promise<{ users: AdminUser[] }>;\n listUsersPaginated(options?: {\n search?: string;\n limit?: number;\n offset?: number;\n orderBy?: string;\n orderDir?: \"asc\" | \"desc\";\n }): Promise<{ users: AdminUser[]; total: number; limit: number; offset: number }>;\n getUser(userId: string): Promise<{ user: AdminUser }>;\n createUser(data: { email: string; displayName?: string; password?: string; roles?: string[]; metadata?: Record<string, any> }): Promise<{ user: AdminUser }>;\n updateUser(userId: string, data: { email?: string; displayName?: string; password?: string; roles?: string[]; metadata?: Record<string, any> }): Promise<{ user: AdminUser }>;\n deleteUser(userId: string): Promise<{ success: boolean }>;\n bootstrap(): Promise<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>;\n}\n\n// ─── Cron API ────────────────────────────────────────────────────────────────\n\n/**\n * Client-side Cron job management interface.\n * @group Cron\n */\nexport interface CronAPI {\n listJobs(): Promise<{ jobs: CronJobStatus[] }>;\n getJob(jobId: string): Promise<{ job: CronJobStatus }>;\n triggerJob(jobId: string): Promise<{ log: CronJobLogEntry; job: CronJobStatus }>;\n getJobLogs(jobId: string, options?: { limit?: number }): Promise<{ logs: CronJobLogEntry[] }>;\n toggleJob(jobId: string, enabled: boolean): Promise<{ job: CronJobStatus }>;\n}\n\n// ─── Functions API ───────────────────────────────────────────────────────────\n\n/**\n * Options for invoking a custom backend function.\n * @group Functions\n */\nexport interface FunctionInvokeOptions {\n /** HTTP method — defaults to `\"POST\"`. */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n /** Sub-path appended after the function name. */\n path?: string;\n /** Extra headers merged into the request. */\n headers?: Record<string, string>;\n}\n\n/**\n * Client interface for invoking custom backend functions.\n * @group Functions\n */\nexport interface FunctionsAPI {\n /**\n * Invoke a custom backend function by name.\n *\n * @typeParam T - Expected shape of the response payload.\n * @param name - Function name (filename without extension, e.g. `\"extract-job\"`).\n * @param payload - Optional JSON-serialisable body sent as POST.\n * @param options - Optional overrides (method, sub-path, headers).\n */\n invoke<T = unknown>(name: string, payload?: unknown, options?: FunctionInvokeOptions): Promise<T>;\n}\n\n// ─── RebaseClient ────────────────────────────────────────────────────────────\n\n/**\n * The single, canonical Rebase client interface.\n *\n * Used everywhere: the server-side `rebase` singleton, the SDK's\n * `createRebaseClient()`, React context, cron job context, etc.\n *\n * Core fields (`data`, `auth`) are always present. Everything else\n * is optional — which capabilities are populated depends on the\n * runtime environment and adapter.\n */\nexport interface RebaseClient<DB = unknown> {\n /** Unified Data access layer */\n data: RebaseData;\n\n /** Unified Authentication layer */\n auth: AuthClient;\n\n /** Unified Storage layer */\n storage?: StorageSource;\n\n /**\n * Server-side email service.\n * Available when SMTP or a custom `sendEmail` function is configured.\n */\n email?: EmailService;\n\n /** Admin API for user management */\n admin?: AdminAPI;\n\n /** Cron job management API */\n cron?: CronAPI;\n\n /** Custom backend functions API */\n functions?: FunctionsAPI;\n\n /** Base HTTP URL of the backend server */\n baseUrl?: string;\n\n /** WebSocket client for realtime subscriptions */\n ws?: unknown;\n\n /** Set the auth token for subsequent requests */\n setToken?(token: string | null): void;\n\n /** Set a function that lazily resolves the auth token */\n setAuthTokenGetter?(getter: () => Promise<string | null>): void;\n\n /** Set handler called when a request returns 401 */\n setOnUnauthorized?(handler: () => Promise<boolean>): void;\n\n /** Resolve the current auth token */\n resolveToken?(): Promise<string | null>;\n\n /** Make a raw HTTP call to the backend */\n call?<T = unknown>(endpoint: string, payload?: unknown): Promise<T>;\n\n /**\n * Execute raw SQL against the database.\n * Only available server-side with a SQL database.\n */\n sql?(query: string, options?: { database?: string; role?: string }): Promise<Record<string, unknown>[]>;\n}\n\n","\nimport type { EntityLinkBuilder } from \"../types/entity_link_builder\";\nimport type { Locale } from \"../types/locales\";\nimport type { EntityAction } from \"../types/entity_actions\";\nimport type { EntityCustomView } from \"../types/entity_views\";\nimport type { RebasePlugin } from \"../types/plugins\";\nimport type { PropertyConfig } from \"../types/property_config\";\nimport type { SlotContribution } from \"../types/slots\";\nimport type { ComponentOverrideMap } from \"../types/component_overrides\";\n\nexport type CustomizationController = {\n\n /**\n * Builder for generating utility links for entities\n */\n entityLinkBuilder?: EntityLinkBuilder;\n\n /**\n * Use plugins to modify the behaviour of the CMS.\n */\n plugins?: RebasePlugin[];\n\n /**\n * Pre-merged slots from plugins + direct slot contributions.\n */\n resolvedSlots: SlotContribution[];\n\n /**\n * List of additional custom views for entities.\n * You can use the key to reference the custom view in\n * the `entityViews` prop of a collection.\n *\n * You can also define an entity view from the UI.\n */\n entityViews?: EntityCustomView[];\n\n /**\n * List of actions that can be performed on entities.\n * These actions are displayed in the entity view and in the collection view.\n * You can later reuse these actions in the `entityActions` prop of a collection,\n * by specifying the `key` of the action.\n */\n entityActions?: EntityAction[];\n\n /**\n * Format of the dates in the CMS.\n * Defaults to 'MMMM dd, yyyy, HH:mm:ss'\n */\n dateTimeFormat?: string;\n\n /**\n * Locale of the CMS, currently only affecting dates\n */\n locale?: Locale;\n\n /**\n * Record of custom form fields to be used in the CMS.\n * You can use the key to reference the custom field in\n * the `propertyConfig` prop of a property in a collection.\n */\n propertyConfigs: Record<string, PropertyConfig>;\n\n /**\n * Global component overrides. Keys are component names from\n * {@link OverridableComponentName}. Values replace the default\n * implementation everywhere in the app.\n *\n * Collection-scoped overrides (set on individual collections)\n * take precedence over global overrides.\n */\n components?: ComponentOverrideMap;\n}\n","import type { Entity } from \"../types/entities\";\nimport type { EntityCollection } from \"../types/collections\";\n\n/**\n * Props used to open a side dialog\n * @group Hooks and utilities\n */\nexport interface EntitySidePanelProps<M extends Record<string, unknown> = Record<string, unknown>> {\n\n /**\n * Absolute path of the entity\n */\n path: string;\n\n /**\n * ID of the entity, if not set, it means we are creating a new entity\n */\n entityId?: string | number;\n\n /**\n * Set this flag to true if you want to make a copy of an existing entity\n */\n copy?: boolean;\n\n /**\n * Open the entity with a selected sub-collection view. If the panel for this\n * entity was already open, it is replaced.\n */\n selectedTab?: string;\n\n /**\n * Use this prop to override the width of the form view.\n * e.g. \"600px\"\n */\n width?: number | string;\n\n /**\n * Collection representing the entities of this view.\n * If you leave it blank it will be induced by your navigation\n */\n collection?: EntityCollection<M>;\n\n /**\n * Should update the URL when opening the dialog.\n * Consider that if the collection that you provide is not defined in the base\n * config of your `Rebase` component, you will not be able to recreate\n * the state if copying the URL to a different window.\n */\n updateUrl?: boolean;\n\n /**\n * Callback when the entity is updated\n * @param params\n */\n onUpdate?: (params: { entity: Entity<M> }) => void;\n\n /**\n * Callback when the dialog is closed\n */\n onClose?: () => void;\n\n /**\n * Should this panel close when saving\n */\n closeOnSave?: boolean;\n\n /**\n * Override some form properties\n */\n formProps?: Record<string, unknown>;\n\n /**\n * Allow the user to open the entity fullscreen\n */\n allowFullScreen?: boolean;\n\n /**\n * Pre-populate the form with these values when creating a new entity.\n * Only applied when `entityId` is not set (i.e. the form is in \"new\" mode).\n * Useful for actions that fetch data from an external source (e.g. a URL)\n * and want to pre-fill the document before the user saves.\n */\n defaultValues?: Partial<M>;\n}\n\n/**\n * Controller to open the side dialog displaying entity forms\n * @group Hooks and utilities\n */\nexport interface SideEntityController {\n /**\n * Close the last panel\n */\n close: () => void;\n\n /**\n * Open a new entity sideDialog. By default, the collection and configuration\n * of the view is fetched from the collections you have specified in the\n * navigation.\n * At least you need to pass the path of the entity you would like\n * to edit. You can set an entityId if you would like to edit and existing one\n * (or a new one with that id).\n * @param props\n */\n open: <M extends Record<string, unknown> = Record<string, unknown>>(props: EntitySidePanelProps<M>) => void;\n\n /**\n * Replace the last open entity panel with the given one.\n * @param props\n */\n replace: <M extends Record<string, unknown> = Record<string, unknown>>(props: EntitySidePanelProps<M>) => void;\n}\n","import React from \"react\";\n\n/**\n * Controller to open the side dialog\n * @group Hooks and utilities\n */\nexport interface SideDialogsController {\n\n /**\n * Close the last panel\n */\n close: () => void;\n\n /**\n * List of side panels currently open\n */\n sidePanels: SideDialogPanelProps[];\n\n /**\n * Override the current side panels\n * @param panels\n */\n setSidePanels: (panels: SideDialogPanelProps[]) => void;\n\n /**\n * Open one or multiple side panels\n * @param props\n */\n open: (panelProps: SideDialogPanelProps | SideDialogPanelProps[]) => void;\n\n /**\n * Replace the last open panel with the given one\n * @param props\n */\n replace: (panelProps: SideDialogPanelProps | SideDialogPanelProps[]) => void;\n}\n\n/**\n * Props used to open a side dialog\n * @group Hooks and utilities\n */\nexport interface SideDialogPanelProps {\n\n /**\n * A key that identifies this panel\n */\n key: string;\n\n /**\n * The component type that will be rendered\n */\n component: React.ReactNode;\n\n /**\n * Optional width of the panel\n */\n width?: string;\n\n /**\n * When open, change the URL to this path.\n * Note that if you want to restore state from a URL you need to add the\n * logic yourself by listening to URL updates, and probably call `open`.\n */\n urlPath?: string;\n\n /**\n * If the navigation stack is empty (you landed in the `urlPath` url), what\n * url path to change to when the panel gets closed.\n */\n parentUrlPath?: string;\n\n /**\n * Callback when the panel is closed\n */\n onClose?: () => void;\n\n /**\n * Use this prop to store additional data in the panel\n */\n additional?: unknown;\n\n}\n","import React from \"react\";\n\n/**\n * Controller to open the side dialog\n * @group Hooks and utilities\n */\nexport interface DialogsController {\n\n /**\n * Close the last dialog\n */\n close: () => void;\n\n /**\n * Open a dialog\n * @param props\n */\n open: <T extends object = object>(props: DialogControllerEntryProps<T>) => { closeDialog: () => void };\n}\n\n/**\n * Props used to open a side dialog\n * @group Hooks and utilities\n */\nexport interface DialogControllerEntryProps<T extends object = object> {\n\n key: string;\n /**\n * The component type that will be rendered\n */\n Component: React.ComponentType<{ open: boolean, closeDialog: () => void } & T>;\n /**\n * Props to pass to the dialog component\n */\n props?: T;\n\n}\n","\n/**\n * Possible snackbar types\n * @group Hooks and utilities\n */\nexport type SnackbarMessageType = \"success\" | \"info\" | \"warning\" | \"error\";\n\n/**\n * Controller to display snackbars\n * @group Hooks and utilities\n */\nexport interface SnackbarController {\n\n /**\n * Close the currently open snackbar\n */\n close: () => void;\n\n /**\n * Display a new snackbar. You need to specify the type and message.\n * You can optionally specify a title\n */\n open: (props: {\n type: SnackbarMessageType;\n message: React.ReactNode;\n autoHideDuration?: number;\n }) => void;\n\n}\n","import { ReactNode } from \"react\";\nimport type { EntityCollection } from \"../types/collections\";\nimport type { EntityCollectionsBuilder } from \"../types/builders\";\nimport type { EntityCustomView } from \"../types/entity_views\";\nimport type { EntityAction } from \"../types/entity_actions\";\nimport type { AppView, NavigationGroupMapping } from \"./navigation\";\nimport type { RebasePlugin } from \"../types/plugins\";\n\n/**\n * Options to enable the built-in collection editor.\n * When provided to `<RebaseCMS>`, the editor is auto-wired as a native feature.\n */\nexport interface CollectionEditorOptions {\n /**\n * Function that returns an auth token for schema-editor API calls.\n * Falls back to `authController.getAuthToken` when omitted.\n */\n getAuthToken?: () => Promise<string | null>;\n /** Mark the editor as read-only (disable mutations). */\n readOnly?: boolean;\n /** Suggested base paths shown when creating new collections. */\n pathSuggestions?: string[];\n}\n\nexport interface RebaseCMSConfig<EC extends EntityCollection = EntityCollection> {\n collections?: EC[] | EntityCollectionsBuilder<EC>;\n homePage?: ReactNode;\n entityViews?: EntityCustomView[];\n entityActions?: EntityAction[];\n plugins?: RebasePlugin[];\n\n /**\n * Centralized configuration for how collections and views are grouped\n * in the navigation sidebar and home page.\n * Each mapping defines a named group and the collection/view slugs\n * that belong to it. The array order determines group display order.\n * Entry order within each group determines card order.\n */\n navigationGroupMappings?: NavigationGroupMapping[];\n\n /**\n * Enable the built-in visual collection/schema editor.\n * Pass `true` for zero-config, or an options object for fine-grained control.\n * When enabled, the editor slots, provider, and Studio schema view\n * are all auto-wired — no plugin or manual view injection needed.\n */\n collectionEditor?: boolean | CollectionEditorOptions;\n}\n\nexport interface RebaseStudioConfig {\n tools?: (\"sql\" | \"js\" | \"rls\" | \"schema\" | \"storage\" | \"cron\" | \"schema-visualizer\" | \"branches\" | \"api\" | \"logs\")[];\n homePage?: ReactNode;\n devViews?: AppView[];\n}\n\nexport interface RebaseAuthConfig {\n loginView?: ReactNode;\n}\n\nexport interface RebaseRegistryController {\n // Current state\n cmsConfig: RebaseCMSConfig | null;\n studioConfig: RebaseStudioConfig | null;\n authConfig: RebaseAuthConfig | null;\n\n // Registration functions\n registerCMS: (config: RebaseCMSConfig) => void;\n unregisterCMS: () => void;\n\n registerStudio: (config: RebaseStudioConfig) => void;\n unregisterStudio: () => void;\n\n registerAuth: (config: RebaseAuthConfig) => void;\n unregisterAuth: () => void;\n}\n","export * from \"./collection_registry\";\nexport * from \"./analytics_controller\";\nexport * from \"./auth\";\n\nexport * from \"./data\";\nexport * from \"./database_admin\";\nexport * from \"./data_driver\";\n\nexport * from \"./local_config_persistence\";\nexport * from \"./navigation\";\nexport * from \"./effective_role\";\n\nexport * from \"./storage\";\nexport * from \"./email\";\nexport * from \"./client\";\nexport * from \"./customization_controller\";\nexport * from \"./side_entity_controller\";\nexport * from \"./side_dialogs_controller\";\nexport * from \"./dialogs_controller\";\nexport * from \"./snackbar\";\nexport * from \"./registry\";\n","\n/**\n * This interface represents a user.\n * It has some of the same fields as a Firebase User.\n * Note that in the default implementation, we simply take the Firebase user\n * and use it as a Rebase user, so that means that even if they are not mapped\n * in this interface, it contains all the methods of the former, such as `delete`,\n * `getIdToken`, etc.\n *\n * @group Models\n */\nexport type User = {\n /**\n * The user's unique ID, scoped to the project.\n */\n readonly uid: string;\n /**\n * The display name of the user.\n */\n readonly displayName: string | null;\n /**\n * The email of the user.\n */\n readonly email: string | null;\n /**\n * The profile photo URL of the user.\n */\n readonly photoURL: string | null;\n /**\n * The provider used to authenticate the user.\n */\n readonly providerId: string;\n /**\n *\n */\n readonly isAnonymous: boolean;\n\n /**\n * Role IDs assigned to this user (e.g. [\"admin\", \"editor\"]).\n */\n roles?: string[];\n\n /**\n * The date and time when the user was created.\n */\n createdAt?: Date | string | null;\n\n /**\n * Additional metadata/custom claims associated with the user.\n * Accessible by the frontend, but only writable by the backend.\n */\n readonly metadata?: Record<string, any>;\n\n getIdToken?: (forceRefresh?: boolean) => Promise<string>;\n\n};\n","export * from \"./user\";\n\n","export * from \"./rebase_context\";\nexport * from \"./types\";\nexport * from \"./controllers\";\nexport * from \"./users\";\n","export const DEFAULT_ONE_OF_TYPE = \"type\"\nexport const DEFAULT_ONE_OF_VALUE = \"value\"\n","const tokenizeRegex = /[A-Z]{2,}(?=[A-Z][a-z]|\\b)|[A-Z]?[a-z]+|[0-9]+(?:[a-z](?![a-z]))?|[A-Z]/g;\n\nexport const toKebabCase = (str?: string) => {\n if (!str || typeof str !== \"string\") return \"\";\n const regExpMatchArray = str.match(tokenizeRegex);\n if (!regExpMatchArray) return \"\";\n return regExpMatchArray\n .map(x => x.toLowerCase())\n .join(\"-\");\n};\n\nconst snakeCaseRegex = tokenizeRegex;\n\nexport const toSnakeCase = (str?: string) => {\n if (!str || typeof str !== \"string\") return \"\";\n const regExpMatchArray = str.match(snakeCaseRegex);\n if (!regExpMatchArray) return \"\";\n return regExpMatchArray\n .map(x => x.toLowerCase())\n .join(\"_\");\n};\n\nexport function camelCase(str: string): string {\n if (!str) return \"\";\n if (str.length === 1) return str.toLowerCase();\n\n // Split by hyphens, underscores, or spaces and filter out empty strings\n const parts = str.split(/[-_ ]+/).filter(Boolean);\n\n if (parts.length === 0) return \"\";\n\n // Start with first part in lowercase\n return parts[0].toLowerCase() +\n // Transform remaining parts to have first letter uppercase\n parts.slice(1)\n .map(part => part.charAt(0).toUpperCase() + part.substring(1).toLowerCase())\n .join(\"\");\n}\n\nexport function randomString(strLength = 5) {\n return Math.random().toString(36).slice(2, 2 + strLength);\n}\n\nexport function randomColor() {\n return Math.floor(Math.random() * 16777215).toString(16);\n}\n\nexport function slugify(text?: string, separator = \"_\", lowercase = true) {\n if (!text) return \"\";\n const from = \"ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;-\"\n const to = `aaaaaeeeeeiiiiooooouuuunc${separator}${separator}${separator}${separator}${separator}${separator}${separator}`;\n\n for (let i = 0, l = from.length; i < l; i++) {\n text = text.replace(new RegExp(from.charAt(i), \"g\"), to.charAt(i));\n }\n\n text = text\n .toString() // Cast to string\n .trim() // Remove whitespace from both sides of a string\n .replace(/^\\s+|\\s+$/g, \"\")\n .replace(/\\s+/g, separator) // Replace spaces with separator\n .replace(/&/g, separator) // Replace & with separator\n .replace(/[^\\w\\\\-]+/g, \"\") // Remove all non-word chars\n .replace(new RegExp(\"\\\\\" + separator + \"\\\\\" + separator + \"+\", \"g\"),\n separator); // Replace multiple separators with single one\n\n return lowercase\n ? text.toLowerCase() // Convert the string to lowercase letters\n : text;\n}\n\nexport function unslugify(slug?: string): string {\n if (!slug) return \"\";\n if (slug.includes(\"-\") || slug.includes(\"_\") || !slug.includes(\" \")) {\n const result = slug.replace(/[-_]/g, \" \");\n return result.replace(/\\w\\S*/g, function (txt) {\n return txt.charAt(0).toUpperCase() + txt.substring(1);\n }).trim();\n } else {\n return slug.trim();\n }\n}\n\nexport function prettifyIdentifier(input: string) {\n if (!input) return \"\";\n\n let text = input;\n\n // 1. Handle camelCase and Acronyms\n // Group 1 ($1 $2): Lowercase followed by Uppercase (e.g., imageURL -> image URL)\n // Group 2 ($3 $4): Uppercase followed by Uppercase+lowercase (e.g., XMLParser -> XML Parser)\n text = text.replace(/([a-z])([A-Z])|([A-Z])([A-Z][a-z])/g, \"$1$3 $2$4\");\n\n // 2. Replace hyphens/underscores with spaces\n text = text.replace(/[_-]+/g, \" \");\n\n // 3. Capitalize first letter of each word (Title Case)\n const s = text\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n return s;\n}\n","!function(e){var t;\"object\"==typeof exports?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(\"undefined\"!=typeof window?t=window:\"undefined\"!=typeof global?t=global:\"undefined\"!=typeof self&&(t=self),t.objectHash=e())}(function(){return function r(o,i,u){function s(n,e){if(!i[n]){if(!o[n]){var t=\"function\"==typeof require&&require;if(!e&&t)return t(n,!0);if(a)return a(n,!0);throw new Error(\"Cannot find module '\"+n+\"'\")}e=i[n]={exports:{}};o[n][0].call(e.exports,function(e){var t=o[n][1][e];return s(t||e)},e,e.exports,r,o,i,u)}return i[n].exports}for(var a=\"function\"==typeof require&&require,e=0;e<u.length;e++)s(u[e]);return s}({1:[function(w,b,m){!function(e,n,s,c,d,h,p,g,y){\"use strict\";var r=w(\"crypto\");function t(e,t){t=u(e,t);var n;return void 0===(n=\"passthrough\"!==t.algorithm?r.createHash(t.algorithm):new l).write&&(n.write=n.update,n.end=n.update),f(t,n).dispatch(e),n.update||n.end(\"\"),n.digest?n.digest(\"buffer\"===t.encoding?void 0:t.encoding):(e=n.read(),\"buffer\"!==t.encoding?e.toString(t.encoding):e)}(m=b.exports=t).sha1=function(e){return t(e)},m.keys=function(e){return t(e,{excludeValues:!0,algorithm:\"sha1\",encoding:\"hex\"})},m.MD5=function(e){return t(e,{algorithm:\"md5\",encoding:\"hex\"})},m.keysMD5=function(e){return t(e,{algorithm:\"md5\",encoding:\"hex\",excludeValues:!0})};var o=r.getHashes?r.getHashes().slice():[\"sha1\",\"md5\"],i=(o.push(\"passthrough\"),[\"buffer\",\"hex\",\"binary\",\"base64\"]);function u(e,t){var n={};if(n.algorithm=(t=t||{}).algorithm||\"sha1\",n.encoding=t.encoding||\"hex\",n.excludeValues=!!t.excludeValues,n.algorithm=n.algorithm.toLowerCase(),n.encoding=n.encoding.toLowerCase(),n.ignoreUnknown=!0===t.ignoreUnknown,n.respectType=!1!==t.respectType,n.respectFunctionNames=!1!==t.respectFunctionNames,n.respectFunctionProperties=!1!==t.respectFunctionProperties,n.unorderedArrays=!0===t.unorderedArrays,n.unorderedSets=!1!==t.unorderedSets,n.unorderedObjects=!1!==t.unorderedObjects,n.replacer=t.replacer||void 0,n.excludeKeys=t.excludeKeys||void 0,void 0===e)throw new Error(\"Object argument required.\");for(var r=0;r<o.length;++r)o[r].toLowerCase()===n.algorithm.toLowerCase()&&(n.algorithm=o[r]);if(-1===o.indexOf(n.algorithm))throw new Error('Algorithm \"'+n.algorithm+'\" not supported. supported values: '+o.join(\", \"));if(-1===i.indexOf(n.encoding)&&\"passthrough\"!==n.algorithm)throw new Error('Encoding \"'+n.encoding+'\" not supported. supported values: '+i.join(\", \"));return n}function a(e){if(\"function\"==typeof e)return null!=/^function\\s+\\w*\\s*\\(\\s*\\)\\s*{\\s+\\[native code\\]\\s+}$/i.exec(Function.prototype.toString.call(e))}function f(o,t,i){i=i||[];function u(e){return t.update?t.update(e,\"utf8\"):t.write(e,\"utf8\")}return{dispatch:function(e){return this[\"_\"+(null===(e=o.replacer?o.replacer(e):e)?\"null\":typeof e)](e)},_object:function(t){var n,e=Object.prototype.toString.call(t),r=/\\[object (.*)\\]/i.exec(e);r=(r=r?r[1]:\"unknown:[\"+e+\"]\").toLowerCase();if(0<=(e=i.indexOf(t)))return this.dispatch(\"[CIRCULAR:\"+e+\"]\");if(i.push(t),void 0!==s&&s.isBuffer&&s.isBuffer(t))return u(\"buffer:\"),u(t);if(\"object\"===r||\"function\"===r||\"asyncfunction\"===r)return e=Object.keys(t),o.unorderedObjects&&(e=e.sort()),!1===o.respectType||a(t)||e.splice(0,0,\"prototype\",\"__proto__\",\"constructor\"),o.excludeKeys&&(e=e.filter(function(e){return!o.excludeKeys(e)})),u(\"object:\"+e.length+\":\"),n=this,e.forEach(function(e){n.dispatch(e),u(\":\"),o.excludeValues||n.dispatch(t[e]),u(\",\")});if(!this[\"_\"+r]){if(o.ignoreUnknown)return u(\"[\"+r+\"]\");throw new Error('Unknown object type \"'+r+'\"')}this[\"_\"+r](t)},_array:function(e,t){t=void 0!==t?t:!1!==o.unorderedArrays;var n=this;if(u(\"array:\"+e.length+\":\"),!t||e.length<=1)return e.forEach(function(e){return n.dispatch(e)});var r=[],t=e.map(function(e){var t=new l,n=i.slice();return f(o,t,n).dispatch(e),r=r.concat(n.slice(i.length)),t.read().toString()});return i=i.concat(r),t.sort(),this._array(t,!1)},_date:function(e){return u(\"date:\"+e.toJSON())},_symbol:function(e){return u(\"symbol:\"+e.toString())},_error:function(e){return u(\"error:\"+e.toString())},_boolean:function(e){return u(\"bool:\"+e.toString())},_string:function(e){u(\"string:\"+e.length+\":\"),u(e.toString())},_function:function(e){u(\"fn:\"),a(e)?this.dispatch(\"[native]\"):this.dispatch(e.toString()),!1!==o.respectFunctionNames&&this.dispatch(\"function-name:\"+String(e.name)),o.respectFunctionProperties&&this._object(e)},_number:function(e){return u(\"number:\"+e.toString())},_xml:function(e){return u(\"xml:\"+e.toString())},_null:function(){return u(\"Null\")},_undefined:function(){return u(\"Undefined\")},_regexp:function(e){return u(\"regex:\"+e.toString())},_uint8array:function(e){return u(\"uint8array:\"),this.dispatch(Array.prototype.slice.call(e))},_uint8clampedarray:function(e){return u(\"uint8clampedarray:\"),this.dispatch(Array.prototype.slice.call(e))},_int8array:function(e){return u(\"int8array:\"),this.dispatch(Array.prototype.slice.call(e))},_uint16array:function(e){return u(\"uint16array:\"),this.dispatch(Array.prototype.slice.call(e))},_int16array:function(e){return u(\"int16array:\"),this.dispatch(Array.prototype.slice.call(e))},_uint32array:function(e){return u(\"uint32array:\"),this.dispatch(Array.prototype.slice.call(e))},_int32array:function(e){return u(\"int32array:\"),this.dispatch(Array.prototype.slice.call(e))},_float32array:function(e){return u(\"float32array:\"),this.dispatch(Array.prototype.slice.call(e))},_float64array:function(e){return u(\"float64array:\"),this.dispatch(Array.prototype.slice.call(e))},_arraybuffer:function(e){return u(\"arraybuffer:\"),this.dispatch(new Uint8Array(e))},_url:function(e){return u(\"url:\"+e.toString())},_map:function(e){u(\"map:\");e=Array.from(e);return this._array(e,!1!==o.unorderedSets)},_set:function(e){u(\"set:\");e=Array.from(e);return this._array(e,!1!==o.unorderedSets)},_file:function(e){return u(\"file:\"),this.dispatch([e.name,e.size,e.type,e.lastModfied])},_blob:function(){if(o.ignoreUnknown)return u(\"[blob]\");throw Error('Hashing Blob objects is currently not supported\\n(see https://github.com/puleos/object-hash/issues/26)\\nUse \"options.replacer\" or \"options.ignoreUnknown\"\\n')},_domwindow:function(){return u(\"domwindow\")},_bigint:function(e){return u(\"bigint:\"+e.toString())},_process:function(){return u(\"process\")},_timer:function(){return u(\"timer\")},_pipe:function(){return u(\"pipe\")},_tcp:function(){return u(\"tcp\")},_udp:function(){return u(\"udp\")},_tty:function(){return u(\"tty\")},_statwatcher:function(){return u(\"statwatcher\")},_securecontext:function(){return u(\"securecontext\")},_connection:function(){return u(\"connection\")},_zlib:function(){return u(\"zlib\")},_context:function(){return u(\"context\")},_nodescript:function(){return u(\"nodescript\")},_httpparser:function(){return u(\"httpparser\")},_dataview:function(){return u(\"dataview\")},_signal:function(){return u(\"signal\")},_fsevent:function(){return u(\"fsevent\")},_tlswrap:function(){return u(\"tlswrap\")}}}function l(){return{buf:\"\",write:function(e){this.buf+=e},end:function(e){this.buf+=e},read:function(){return this.buf}}}m.writeToStream=function(e,t,n){return void 0===n&&(n=t,t={}),f(t=u(e,t),n).dispatch(e)}}.call(this,w(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},w(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/fake_9a5aa49d.js\",\"/\")},{buffer:3,crypto:5,lYpoI2:11}],2:[function(e,t,f){!function(e,t,n,r,o,i,u,s,a){!function(e){\"use strict\";var a=\"undefined\"!=typeof Uint8Array?Uint8Array:Array,t=\"+\".charCodeAt(0),n=\"/\".charCodeAt(0),r=\"0\".charCodeAt(0),o=\"a\".charCodeAt(0),i=\"A\".charCodeAt(0),u=\"-\".charCodeAt(0),s=\"_\".charCodeAt(0);function f(e){e=e.charCodeAt(0);return e===t||e===u?62:e===n||e===s?63:e<r?-1:e<r+10?e-r+26+26:e<i+26?e-i:e<o+26?e-o+26:void 0}e.toByteArray=function(e){var t,n;if(0<e.length%4)throw new Error(\"Invalid string. Length must be a multiple of 4\");var r=e.length,r=\"=\"===e.charAt(r-2)?2:\"=\"===e.charAt(r-1)?1:0,o=new a(3*e.length/4-r),i=0<r?e.length-4:e.length,u=0;function s(e){o[u++]=e}for(t=0;t<i;t+=4,0)s((16711680&(n=f(e.charAt(t))<<18|f(e.charAt(t+1))<<12|f(e.charAt(t+2))<<6|f(e.charAt(t+3))))>>16),s((65280&n)>>8),s(255&n);return 2==r?s(255&(n=f(e.charAt(t))<<2|f(e.charAt(t+1))>>4)):1==r&&(s((n=f(e.charAt(t))<<10|f(e.charAt(t+1))<<4|f(e.charAt(t+2))>>2)>>8&255),s(255&n)),o},e.fromByteArray=function(e){var t,n,r,o,i=e.length%3,u=\"\";function s(e){return\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".charAt(e)}for(t=0,r=e.length-i;t<r;t+=3)n=(e[t]<<16)+(e[t+1]<<8)+e[t+2],u+=s((o=n)>>18&63)+s(o>>12&63)+s(o>>6&63)+s(63&o);switch(i){case 1:u=(u+=s((n=e[e.length-1])>>2))+s(n<<4&63)+\"==\";break;case 2:u=(u=(u+=s((n=(e[e.length-2]<<8)+e[e.length-1])>>10))+s(n>>4&63))+s(n<<2&63)+\"=\"}return u}}(void 0===f?this.base64js={}:f)}.call(this,e(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},e(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/base64-js/lib/b64.js\",\"/node_modules/gulp-browserify/node_modules/base64-js/lib\")},{buffer:3,lYpoI2:11}],3:[function(O,e,H){!function(e,n,f,r,h,p,g,y,w){var a=O(\"base64-js\"),i=O(\"ieee754\");function f(e,t,n){if(!(this instanceof f))return new f(e,t,n);var r,o,i,u,s=typeof e;if(\"base64\"===t&&\"string\"==s)for(e=(u=e).trim?u.trim():u.replace(/^\\s+|\\s+$/g,\"\");e.length%4!=0;)e+=\"=\";if(\"number\"==s)r=j(e);else if(\"string\"==s)r=f.byteLength(e,t);else{if(\"object\"!=s)throw new Error(\"First argument needs to be a number, array or string.\");r=j(e.length)}if(f._useTypedArrays?o=f._augment(new Uint8Array(r)):((o=this).length=r,o._isBuffer=!0),f._useTypedArrays&&\"number\"==typeof e.byteLength)o._set(e);else if(C(u=e)||f.isBuffer(u)||u&&\"object\"==typeof u&&\"number\"==typeof u.length)for(i=0;i<r;i++)f.isBuffer(e)?o[i]=e.readUInt8(i):o[i]=e[i];else if(\"string\"==s)o.write(e,0,t);else if(\"number\"==s&&!f._useTypedArrays&&!n)for(i=0;i<r;i++)o[i]=0;return o}function b(e,t,n,r){return f._charsWritten=c(function(e){for(var t=[],n=0;n<e.length;n++)t.push(255&e.charCodeAt(n));return t}(t),e,n,r)}function m(e,t,n,r){return f._charsWritten=c(function(e){for(var t,n,r=[],o=0;o<e.length;o++)n=e.charCodeAt(o),t=n>>8,n=n%256,r.push(n),r.push(t);return r}(t),e,n,r)}function v(e,t,n){var r=\"\";n=Math.min(e.length,n);for(var o=t;o<n;o++)r+=String.fromCharCode(e[o]);return r}function o(e,t,n,r){r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(null!=t,\"missing offset\"),d(t+1<e.length,\"Trying to read beyond buffer length\"));var o,r=e.length;if(!(r<=t))return n?(o=e[t],t+1<r&&(o|=e[t+1]<<8)):(o=e[t]<<8,t+1<r&&(o|=e[t+1])),o}function u(e,t,n,r){r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(null!=t,\"missing offset\"),d(t+3<e.length,\"Trying to read beyond buffer length\"));var o,r=e.length;if(!(r<=t))return n?(t+2<r&&(o=e[t+2]<<16),t+1<r&&(o|=e[t+1]<<8),o|=e[t],t+3<r&&(o+=e[t+3]<<24>>>0)):(t+1<r&&(o=e[t+1]<<16),t+2<r&&(o|=e[t+2]<<8),t+3<r&&(o|=e[t+3]),o+=e[t]<<24>>>0),o}function _(e,t,n,r){if(r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(null!=t,\"missing offset\"),d(t+1<e.length,\"Trying to read beyond buffer length\")),!(e.length<=t))return r=o(e,t,n,!0),32768&r?-1*(65535-r+1):r}function E(e,t,n,r){if(r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(null!=t,\"missing offset\"),d(t+3<e.length,\"Trying to read beyond buffer length\")),!(e.length<=t))return r=u(e,t,n,!0),2147483648&r?-1*(4294967295-r+1):r}function I(e,t,n,r){return r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(t+3<e.length,\"Trying to read beyond buffer length\")),i.read(e,t,n,23,4)}function A(e,t,n,r){return r||(d(\"boolean\"==typeof n,\"missing or invalid endian\"),d(t+7<e.length,\"Trying to read beyond buffer length\")),i.read(e,t,n,52,8)}function s(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+1<e.length,\"trying to write beyond buffer length\"),Y(t,65535));o=e.length;if(!(o<=n))for(var i=0,u=Math.min(o-n,2);i<u;i++)e[n+i]=(t&255<<8*(r?i:1-i))>>>8*(r?i:1-i)}function l(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+3<e.length,\"trying to write beyond buffer length\"),Y(t,4294967295));o=e.length;if(!(o<=n))for(var i=0,u=Math.min(o-n,4);i<u;i++)e[n+i]=t>>>8*(r?i:3-i)&255}function B(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+1<e.length,\"Trying to write beyond buffer length\"),F(t,32767,-32768)),e.length<=n||s(e,0<=t?t:65535+t+1,n,r,o)}function L(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+3<e.length,\"Trying to write beyond buffer length\"),F(t,2147483647,-2147483648)),e.length<=n||l(e,0<=t?t:4294967295+t+1,n,r,o)}function U(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+3<e.length,\"Trying to write beyond buffer length\"),D(t,34028234663852886e22,-34028234663852886e22)),e.length<=n||i.write(e,t,n,r,23,4)}function x(e,t,n,r,o){o||(d(null!=t,\"missing value\"),d(\"boolean\"==typeof r,\"missing or invalid endian\"),d(null!=n,\"missing offset\"),d(n+7<e.length,\"Trying to write beyond buffer length\"),D(t,17976931348623157e292,-17976931348623157e292)),e.length<=n||i.write(e,t,n,r,52,8)}H.Buffer=f,H.SlowBuffer=f,H.INSPECT_MAX_BYTES=50,f.poolSize=8192,f._useTypedArrays=function(){try{var e=new ArrayBuffer(0),t=new Uint8Array(e);return t.foo=function(){return 42},42===t.foo()&&\"function\"==typeof t.subarray}catch(e){return!1}}(),f.isEncoding=function(e){switch(String(e).toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"binary\":case\"base64\":case\"raw\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return!0;default:return!1}},f.isBuffer=function(e){return!(null==e||!e._isBuffer)},f.byteLength=function(e,t){var n;switch(e+=\"\",t||\"utf8\"){case\"hex\":n=e.length/2;break;case\"utf8\":case\"utf-8\":n=T(e).length;break;case\"ascii\":case\"binary\":case\"raw\":n=e.length;break;case\"base64\":n=M(e).length;break;case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":n=2*e.length;break;default:throw new Error(\"Unknown encoding\")}return n},f.concat=function(e,t){if(d(C(e),\"Usage: Buffer.concat(list, [totalLength])\\nlist should be an Array.\"),0===e.length)return new f(0);if(1===e.length)return e[0];if(\"number\"!=typeof t)for(o=t=0;o<e.length;o++)t+=e[o].length;for(var n=new f(t),r=0,o=0;o<e.length;o++){var i=e[o];i.copy(n,r),r+=i.length}return n},f.prototype.write=function(e,t,n,r){isFinite(t)?isFinite(n)||(r=n,n=void 0):(a=r,r=t,t=n,n=a),t=Number(t)||0;var o,i,u,s,a=this.length-t;switch((!n||a<(n=Number(n)))&&(n=a),r=String(r||\"utf8\").toLowerCase()){case\"hex\":o=function(e,t,n,r){n=Number(n)||0;var o=e.length-n;(!r||o<(r=Number(r)))&&(r=o),d((o=t.length)%2==0,\"Invalid hex string\"),o/2<r&&(r=o/2);for(var i=0;i<r;i++){var u=parseInt(t.substr(2*i,2),16);d(!isNaN(u),\"Invalid hex string\"),e[n+i]=u}return f._charsWritten=2*i,i}(this,e,t,n);break;case\"utf8\":case\"utf-8\":i=this,u=t,s=n,o=f._charsWritten=c(T(e),i,u,s);break;case\"ascii\":case\"binary\":o=b(this,e,t,n);break;case\"base64\":i=this,u=t,s=n,o=f._charsWritten=c(M(e),i,u,s);break;case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":o=m(this,e,t,n);break;default:throw new Error(\"Unknown encoding\")}return o},f.prototype.toString=function(e,t,n){var r,o,i,u,s=this;if(e=String(e||\"utf8\").toLowerCase(),t=Number(t)||0,(n=void 0!==n?Number(n):s.length)===t)return\"\";switch(e){case\"hex\":r=function(e,t,n){var r=e.length;(!t||t<0)&&(t=0);(!n||n<0||r<n)&&(n=r);for(var o=\"\",i=t;i<n;i++)o+=k(e[i]);return o}(s,t,n);break;case\"utf8\":case\"utf-8\":r=function(e,t,n){var r=\"\",o=\"\";n=Math.min(e.length,n);for(var i=t;i<n;i++)e[i]<=127?(r+=N(o)+String.fromCharCode(e[i]),o=\"\"):o+=\"%\"+e[i].toString(16);return r+N(o)}(s,t,n);break;case\"ascii\":case\"binary\":r=v(s,t,n);break;case\"base64\":o=s,u=n,r=0===(i=t)&&u===o.length?a.fromByteArray(o):a.fromByteArray(o.slice(i,u));break;case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":r=function(e,t,n){for(var r=e.slice(t,n),o=\"\",i=0;i<r.length;i+=2)o+=String.fromCharCode(r[i]+256*r[i+1]);return o}(s,t,n);break;default:throw new Error(\"Unknown encoding\")}return r},f.prototype.toJSON=function(){return{type:\"Buffer\",data:Array.prototype.slice.call(this._arr||this,0)}},f.prototype.copy=function(e,t,n,r){if(t=t||0,(r=r||0===r?r:this.length)!==(n=n||0)&&0!==e.length&&0!==this.length){d(n<=r,\"sourceEnd < sourceStart\"),d(0<=t&&t<e.length,\"targetStart out of bounds\"),d(0<=n&&n<this.length,\"sourceStart out of bounds\"),d(0<=r&&r<=this.length,\"sourceEnd out of bounds\"),r>this.length&&(r=this.length);var o=(r=e.length-t<r-n?e.length-t+n:r)-n;if(o<100||!f._useTypedArrays)for(var i=0;i<o;i++)e[i+t]=this[i+n];else e._set(this.subarray(n,n+o),t)}},f.prototype.slice=function(e,t){var n=this.length;if(e=S(e,n,0),t=S(t,n,n),f._useTypedArrays)return f._augment(this.subarray(e,t));for(var r=t-e,o=new f(r,void 0,!0),i=0;i<r;i++)o[i]=this[i+e];return o},f.prototype.get=function(e){return console.log(\".get() is deprecated. Access using array indexes instead.\"),this.readUInt8(e)},f.prototype.set=function(e,t){return console.log(\".set() is deprecated. Access using array indexes instead.\"),this.writeUInt8(e,t)},f.prototype.readUInt8=function(e,t){if(t||(d(null!=e,\"missing offset\"),d(e<this.length,\"Trying to read beyond buffer length\")),!(e>=this.length))return this[e]},f.prototype.readUInt16LE=function(e,t){return o(this,e,!0,t)},f.prototype.readUInt16BE=function(e,t){return o(this,e,!1,t)},f.prototype.readUInt32LE=function(e,t){return u(this,e,!0,t)},f.prototype.readUInt32BE=function(e,t){return u(this,e,!1,t)},f.prototype.readInt8=function(e,t){if(t||(d(null!=e,\"missing offset\"),d(e<this.length,\"Trying to read beyond buffer length\")),!(e>=this.length))return 128&this[e]?-1*(255-this[e]+1):this[e]},f.prototype.readInt16LE=function(e,t){return _(this,e,!0,t)},f.prototype.readInt16BE=function(e,t){return _(this,e,!1,t)},f.prototype.readInt32LE=function(e,t){return E(this,e,!0,t)},f.prototype.readInt32BE=function(e,t){return E(this,e,!1,t)},f.prototype.readFloatLE=function(e,t){return I(this,e,!0,t)},f.prototype.readFloatBE=function(e,t){return I(this,e,!1,t)},f.prototype.readDoubleLE=function(e,t){return A(this,e,!0,t)},f.prototype.readDoubleBE=function(e,t){return A(this,e,!1,t)},f.prototype.writeUInt8=function(e,t,n){n||(d(null!=e,\"missing value\"),d(null!=t,\"missing offset\"),d(t<this.length,\"trying to write beyond buffer length\"),Y(e,255)),t>=this.length||(this[t]=e)},f.prototype.writeUInt16LE=function(e,t,n){s(this,e,t,!0,n)},f.prototype.writeUInt16BE=function(e,t,n){s(this,e,t,!1,n)},f.prototype.writeUInt32LE=function(e,t,n){l(this,e,t,!0,n)},f.prototype.writeUInt32BE=function(e,t,n){l(this,e,t,!1,n)},f.prototype.writeInt8=function(e,t,n){n||(d(null!=e,\"missing value\"),d(null!=t,\"missing offset\"),d(t<this.length,\"Trying to write beyond buffer length\"),F(e,127,-128)),t>=this.length||(0<=e?this.writeUInt8(e,t,n):this.writeUInt8(255+e+1,t,n))},f.prototype.writeInt16LE=function(e,t,n){B(this,e,t,!0,n)},f.prototype.writeInt16BE=function(e,t,n){B(this,e,t,!1,n)},f.prototype.writeInt32LE=function(e,t,n){L(this,e,t,!0,n)},f.prototype.writeInt32BE=function(e,t,n){L(this,e,t,!1,n)},f.prototype.writeFloatLE=function(e,t,n){U(this,e,t,!0,n)},f.prototype.writeFloatBE=function(e,t,n){U(this,e,t,!1,n)},f.prototype.writeDoubleLE=function(e,t,n){x(this,e,t,!0,n)},f.prototype.writeDoubleBE=function(e,t,n){x(this,e,t,!1,n)},f.prototype.fill=function(e,t,n){if(t=t||0,n=n||this.length,d(\"number\"==typeof(e=\"string\"==typeof(e=e||0)?e.charCodeAt(0):e)&&!isNaN(e),\"value is not a number\"),d(t<=n,\"end < start\"),n!==t&&0!==this.length){d(0<=t&&t<this.length,\"start out of bounds\"),d(0<=n&&n<=this.length,\"end out of bounds\");for(var r=t;r<n;r++)this[r]=e}},f.prototype.inspect=function(){for(var e=[],t=this.length,n=0;n<t;n++)if(e[n]=k(this[n]),n===H.INSPECT_MAX_BYTES){e[n+1]=\"...\";break}return\"<Buffer \"+e.join(\" \")+\">\"},f.prototype.toArrayBuffer=function(){if(\"undefined\"==typeof Uint8Array)throw new Error(\"Buffer.toArrayBuffer not supported in this browser\");if(f._useTypedArrays)return new f(this).buffer;for(var e=new Uint8Array(this.length),t=0,n=e.length;t<n;t+=1)e[t]=this[t];return e.buffer};var t=f.prototype;function S(e,t,n){return\"number\"!=typeof e?n:t<=(e=~~e)?t:0<=e||0<=(e+=t)?e:0}function j(e){return(e=~~Math.ceil(+e))<0?0:e}function C(e){return(Array.isArray||function(e){return\"[object Array]\"===Object.prototype.toString.call(e)})(e)}function k(e){return e<16?\"0\"+e.toString(16):e.toString(16)}function T(e){for(var t=[],n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<=127)t.push(e.charCodeAt(n));else for(var o=n,i=(55296<=r&&r<=57343&&n++,encodeURIComponent(e.slice(o,n+1)).substr(1).split(\"%\")),u=0;u<i.length;u++)t.push(parseInt(i[u],16))}return t}function M(e){return a.toByteArray(e)}function c(e,t,n,r){for(var o=0;o<r&&!(o+n>=t.length||o>=e.length);o++)t[o+n]=e[o];return o}function N(e){try{return decodeURIComponent(e)}catch(e){return String.fromCharCode(65533)}}function Y(e,t){d(\"number\"==typeof e,\"cannot write a non-number as a number\"),d(0<=e,\"specified a negative value for writing an unsigned value\"),d(e<=t,\"value is larger than maximum value for type\"),d(Math.floor(e)===e,\"value has a fractional component\")}function F(e,t,n){d(\"number\"==typeof e,\"cannot write a non-number as a number\"),d(e<=t,\"value larger than maximum allowed value\"),d(n<=e,\"value smaller than minimum allowed value\"),d(Math.floor(e)===e,\"value has a fractional component\")}function D(e,t,n){d(\"number\"==typeof e,\"cannot write a non-number as a number\"),d(e<=t,\"value larger than maximum allowed value\"),d(n<=e,\"value smaller than minimum allowed value\")}function d(e,t){if(!e)throw new Error(t||\"Failed assertion\")}f._augment=function(e){return e._isBuffer=!0,e._get=e.get,e._set=e.set,e.get=t.get,e.set=t.set,e.write=t.write,e.toString=t.toString,e.toLocaleString=t.toString,e.toJSON=t.toJSON,e.copy=t.copy,e.slice=t.slice,e.readUInt8=t.readUInt8,e.readUInt16LE=t.readUInt16LE,e.readUInt16BE=t.readUInt16BE,e.readUInt32LE=t.readUInt32LE,e.readUInt32BE=t.readUInt32BE,e.readInt8=t.readInt8,e.readInt16LE=t.readInt16LE,e.readInt16BE=t.readInt16BE,e.readInt32LE=t.readInt32LE,e.readInt32BE=t.readInt32BE,e.readFloatLE=t.readFloatLE,e.readFloatBE=t.readFloatBE,e.readDoubleLE=t.readDoubleLE,e.readDoubleBE=t.readDoubleBE,e.writeUInt8=t.writeUInt8,e.writeUInt16LE=t.writeUInt16LE,e.writeUInt16BE=t.writeUInt16BE,e.writeUInt32LE=t.writeUInt32LE,e.writeUInt32BE=t.writeUInt32BE,e.writeInt8=t.writeInt8,e.writeInt16LE=t.writeInt16LE,e.writeInt16BE=t.writeInt16BE,e.writeInt32LE=t.writeInt32LE,e.writeInt32BE=t.writeInt32BE,e.writeFloatLE=t.writeFloatLE,e.writeFloatBE=t.writeFloatBE,e.writeDoubleLE=t.writeDoubleLE,e.writeDoubleBE=t.writeDoubleBE,e.fill=t.fill,e.inspect=t.inspect,e.toArrayBuffer=t.toArrayBuffer,e}}.call(this,O(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},O(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/buffer/index.js\",\"/node_modules/gulp-browserify/node_modules/buffer\")},{\"base64-js\":2,buffer:3,ieee754:10,lYpoI2:11}],4:[function(c,d,e){!function(e,t,a,n,r,o,i,u,s){var a=c(\"buffer\").Buffer,f=4,l=new a(f);l.fill(0);d.exports={hash:function(e,t,n,r){for(var o=t(function(e,t){e.length%f!=0&&(n=e.length+(f-e.length%f),e=a.concat([e,l],n));for(var n,r=[],o=t?e.readInt32BE:e.readInt32LE,i=0;i<e.length;i+=f)r.push(o.call(e,i));return r}(e=a.isBuffer(e)?e:new a(e),r),8*e.length),t=r,i=new a(n),u=t?i.writeInt32BE:i.writeInt32LE,s=0;s<o.length;s++)u.call(i,o[s],4*s,!0);return i}}}.call(this,c(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},c(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/helpers.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{buffer:3,lYpoI2:11}],5:[function(v,e,_){!function(l,c,u,d,h,p,g,y,w){var u=v(\"buffer\").Buffer,e=v(\"./sha\"),t=v(\"./sha256\"),n=v(\"./rng\"),b={sha1:e,sha256:t,md5:v(\"./md5\")},s=64,a=new u(s);function r(e,n){var r=b[e=e||\"sha1\"],o=[];return r||i(\"algorithm:\",e,\"is not yet supported\"),{update:function(e){return u.isBuffer(e)||(e=new u(e)),o.push(e),e.length,this},digest:function(e){var t=u.concat(o),t=n?function(e,t,n){u.isBuffer(t)||(t=new u(t)),u.isBuffer(n)||(n=new u(n)),t.length>s?t=e(t):t.length<s&&(t=u.concat([t,a],s));for(var r=new u(s),o=new u(s),i=0;i<s;i++)r[i]=54^t[i],o[i]=92^t[i];return n=e(u.concat([r,n])),e(u.concat([o,n]))}(r,n,t):r(t);return o=null,e?t.toString(e):t}}}function i(){var e=[].slice.call(arguments).join(\" \");throw new Error([e,\"we accept pull requests\",\"http://github.com/dominictarr/crypto-browserify\"].join(\"\\n\"))}a.fill(0),_.createHash=function(e){return r(e)},_.createHmac=r,_.randomBytes=function(e,t){if(!t||!t.call)return new u(n(e));try{t.call(this,void 0,new u(n(e)))}catch(e){t(e)}};var o,f=[\"createCredentials\",\"createCipher\",\"createCipheriv\",\"createDecipher\",\"createDecipheriv\",\"createSign\",\"createVerify\",\"createDiffieHellman\",\"pbkdf2\"],m=function(e){_[e]=function(){i(\"sorry,\",e,\"is not implemented yet\")}};for(o in f)m(f[o],o)}.call(this,v(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},v(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/index.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{\"./md5\":6,\"./rng\":7,\"./sha\":8,\"./sha256\":9,buffer:3,lYpoI2:11}],6:[function(w,b,e){!function(e,r,o,i,u,a,f,l,y){var t=w(\"./helpers\");function n(e,t){e[t>>5]|=128<<t%32,e[14+(t+64>>>9<<4)]=t;for(var n=1732584193,r=-271733879,o=-1732584194,i=271733878,u=0;u<e.length;u+=16){var s=n,a=r,f=o,l=i,n=c(n,r,o,i,e[u+0],7,-680876936),i=c(i,n,r,o,e[u+1],12,-389564586),o=c(o,i,n,r,e[u+2],17,606105819),r=c(r,o,i,n,e[u+3],22,-1044525330);n=c(n,r,o,i,e[u+4],7,-176418897),i=c(i,n,r,o,e[u+5],12,1200080426),o=c(o,i,n,r,e[u+6],17,-1473231341),r=c(r,o,i,n,e[u+7],22,-45705983),n=c(n,r,o,i,e[u+8],7,1770035416),i=c(i,n,r,o,e[u+9],12,-1958414417),o=c(o,i,n,r,e[u+10],17,-42063),r=c(r,o,i,n,e[u+11],22,-1990404162),n=c(n,r,o,i,e[u+12],7,1804603682),i=c(i,n,r,o,e[u+13],12,-40341101),o=c(o,i,n,r,e[u+14],17,-1502002290),n=d(n,r=c(r,o,i,n,e[u+15],22,1236535329),o,i,e[u+1],5,-165796510),i=d(i,n,r,o,e[u+6],9,-1069501632),o=d(o,i,n,r,e[u+11],14,643717713),r=d(r,o,i,n,e[u+0],20,-373897302),n=d(n,r,o,i,e[u+5],5,-701558691),i=d(i,n,r,o,e[u+10],9,38016083),o=d(o,i,n,r,e[u+15],14,-660478335),r=d(r,o,i,n,e[u+4],20,-405537848),n=d(n,r,o,i,e[u+9],5,568446438),i=d(i,n,r,o,e[u+14],9,-1019803690),o=d(o,i,n,r,e[u+3],14,-187363961),r=d(r,o,i,n,e[u+8],20,1163531501),n=d(n,r,o,i,e[u+13],5,-1444681467),i=d(i,n,r,o,e[u+2],9,-51403784),o=d(o,i,n,r,e[u+7],14,1735328473),n=h(n,r=d(r,o,i,n,e[u+12],20,-1926607734),o,i,e[u+5],4,-378558),i=h(i,n,r,o,e[u+8],11,-2022574463),o=h(o,i,n,r,e[u+11],16,1839030562),r=h(r,o,i,n,e[u+14],23,-35309556),n=h(n,r,o,i,e[u+1],4,-1530992060),i=h(i,n,r,o,e[u+4],11,1272893353),o=h(o,i,n,r,e[u+7],16,-155497632),r=h(r,o,i,n,e[u+10],23,-1094730640),n=h(n,r,o,i,e[u+13],4,681279174),i=h(i,n,r,o,e[u+0],11,-358537222),o=h(o,i,n,r,e[u+3],16,-722521979),r=h(r,o,i,n,e[u+6],23,76029189),n=h(n,r,o,i,e[u+9],4,-640364487),i=h(i,n,r,o,e[u+12],11,-421815835),o=h(o,i,n,r,e[u+15],16,530742520),n=p(n,r=h(r,o,i,n,e[u+2],23,-995338651),o,i,e[u+0],6,-198630844),i=p(i,n,r,o,e[u+7],10,1126891415),o=p(o,i,n,r,e[u+14],15,-1416354905),r=p(r,o,i,n,e[u+5],21,-57434055),n=p(n,r,o,i,e[u+12],6,1700485571),i=p(i,n,r,o,e[u+3],10,-1894986606),o=p(o,i,n,r,e[u+10],15,-1051523),r=p(r,o,i,n,e[u+1],21,-2054922799),n=p(n,r,o,i,e[u+8],6,1873313359),i=p(i,n,r,o,e[u+15],10,-30611744),o=p(o,i,n,r,e[u+6],15,-1560198380),r=p(r,o,i,n,e[u+13],21,1309151649),n=p(n,r,o,i,e[u+4],6,-145523070),i=p(i,n,r,o,e[u+11],10,-1120210379),o=p(o,i,n,r,e[u+2],15,718787259),r=p(r,o,i,n,e[u+9],21,-343485551),n=g(n,s),r=g(r,a),o=g(o,f),i=g(i,l)}return Array(n,r,o,i)}function s(e,t,n,r,o,i){return g((t=g(g(t,e),g(r,i)))<<o|t>>>32-o,n)}function c(e,t,n,r,o,i,u){return s(t&n|~t&r,e,t,o,i,u)}function d(e,t,n,r,o,i,u){return s(t&r|n&~r,e,t,o,i,u)}function h(e,t,n,r,o,i,u){return s(t^n^r,e,t,o,i,u)}function p(e,t,n,r,o,i,u){return s(n^(t|~r),e,t,o,i,u)}function g(e,t){var n=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(n>>16)<<16|65535&n}b.exports=function(e){return t.hash(e,n,16)}}.call(this,w(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},w(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/md5.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{\"./helpers\":4,buffer:3,lYpoI2:11}],7:[function(e,l,t){!function(e,t,n,r,o,i,u,s,f){var a;l.exports=a||function(e){for(var t,n=new Array(e),r=0;r<e;r++)0==(3&r)&&(t=4294967296*Math.random()),n[r]=t>>>((3&r)<<3)&255;return n}}.call(this,e(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},e(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/rng.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{buffer:3,lYpoI2:11}],8:[function(c,d,e){!function(e,t,n,r,o,s,a,f,l){var i=c(\"./helpers\");function u(l,c){l[c>>5]|=128<<24-c%32,l[15+(c+64>>9<<4)]=c;for(var e,t,n,r=Array(80),o=1732584193,i=-271733879,u=-1732584194,s=271733878,d=-1009589776,h=0;h<l.length;h+=16){for(var p=o,g=i,y=u,w=s,b=d,a=0;a<80;a++){r[a]=a<16?l[h+a]:v(r[a-3]^r[a-8]^r[a-14]^r[a-16],1);var f=m(m(v(o,5),(f=i,t=u,n=s,(e=a)<20?f&t|~f&n:!(e<40)&&e<60?f&t|f&n|t&n:f^t^n)),m(m(d,r[a]),(e=a)<20?1518500249:e<40?1859775393:e<60?-1894007588:-899497514)),d=s,s=u,u=v(i,30),i=o,o=f}o=m(o,p),i=m(i,g),u=m(u,y),s=m(s,w),d=m(d,b)}return Array(o,i,u,s,d)}function m(e,t){var n=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(n>>16)<<16|65535&n}function v(e,t){return e<<t|e>>>32-t}d.exports=function(e){return i.hash(e,u,20,!0)}}.call(this,c(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},c(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/sha.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{\"./helpers\":4,buffer:3,lYpoI2:11}],9:[function(c,d,e){!function(e,t,n,r,u,s,a,f,l){function b(e,t){var n=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(n>>16)<<16|65535&n}function o(e,l){var c,d=new Array(1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298),t=new Array(1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225),n=new Array(64);e[l>>5]|=128<<24-l%32,e[15+(l+64>>9<<4)]=l;for(var r,o,h=0;h<e.length;h+=16){for(var i=t[0],u=t[1],s=t[2],p=t[3],a=t[4],g=t[5],y=t[6],w=t[7],f=0;f<64;f++)n[f]=f<16?e[f+h]:b(b(b((o=n[f-2],m(o,17)^m(o,19)^v(o,10)),n[f-7]),(o=n[f-15],m(o,7)^m(o,18)^v(o,3))),n[f-16]),c=b(b(b(b(w,m(o=a,6)^m(o,11)^m(o,25)),a&g^~a&y),d[f]),n[f]),r=b(m(r=i,2)^m(r,13)^m(r,22),i&u^i&s^u&s),w=y,y=g,g=a,a=b(p,c),p=s,s=u,u=i,i=b(c,r);t[0]=b(i,t[0]),t[1]=b(u,t[1]),t[2]=b(s,t[2]),t[3]=b(p,t[3]),t[4]=b(a,t[4]),t[5]=b(g,t[5]),t[6]=b(y,t[6]),t[7]=b(w,t[7])}return t}var i=c(\"./helpers\"),m=function(e,t){return e>>>t|e<<32-t},v=function(e,t){return e>>>t};d.exports=function(e){return i.hash(e,o,32,!0)}}.call(this,c(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},c(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/crypto-browserify/sha256.js\",\"/node_modules/gulp-browserify/node_modules/crypto-browserify\")},{\"./helpers\":4,buffer:3,lYpoI2:11}],10:[function(e,t,f){!function(e,t,n,r,o,i,u,s,a){f.read=function(e,t,n,r,o){var i,u,l=8*o-r-1,c=(1<<l)-1,d=c>>1,s=-7,a=n?o-1:0,f=n?-1:1,o=e[t+a];for(a+=f,i=o&(1<<-s)-1,o>>=-s,s+=l;0<s;i=256*i+e[t+a],a+=f,s-=8);for(u=i&(1<<-s)-1,i>>=-s,s+=r;0<s;u=256*u+e[t+a],a+=f,s-=8);if(0===i)i=1-d;else{if(i===c)return u?NaN:1/0*(o?-1:1);u+=Math.pow(2,r),i-=d}return(o?-1:1)*u*Math.pow(2,i-r)},f.write=function(e,t,l,n,r,c){var o,i,u=8*c-r-1,s=(1<<u)-1,a=s>>1,d=23===r?Math.pow(2,-24)-Math.pow(2,-77):0,f=n?0:c-1,h=n?1:-1,c=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(i=isNaN(t)?1:0,o=s):(o=Math.floor(Math.log(t)/Math.LN2),t*(n=Math.pow(2,-o))<1&&(o--,n*=2),2<=(t+=1<=o+a?d/n:d*Math.pow(2,1-a))*n&&(o++,n/=2),s<=o+a?(i=0,o=s):1<=o+a?(i=(t*n-1)*Math.pow(2,r),o+=a):(i=t*Math.pow(2,a-1)*Math.pow(2,r),o=0));8<=r;e[l+f]=255&i,f+=h,i/=256,r-=8);for(o=o<<r|i,u+=r;0<u;e[l+f]=255&o,f+=h,o/=256,u-=8);e[l+f-h]|=128*c}}.call(this,e(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},e(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/ieee754/index.js\",\"/node_modules/gulp-browserify/node_modules/ieee754\")},{buffer:3,lYpoI2:11}],11:[function(e,h,t){!function(e,t,n,r,o,f,l,c,d){var i,u,s;function a(){}(e=h.exports={}).nextTick=(u=\"undefined\"!=typeof window&&window.setImmediate,s=\"undefined\"!=typeof window&&window.postMessage&&window.addEventListener,u?function(e){return window.setImmediate(e)}:s?(i=[],window.addEventListener(\"message\",function(e){var t=e.source;t!==window&&null!==t||\"process-tick\"!==e.data||(e.stopPropagation(),0<i.length&&i.shift()())},!0),function(e){i.push(e),window.postMessage(\"process-tick\",\"*\")}):function(e){setTimeout(e,0)}),e.title=\"browser\",e.browser=!0,e.env={},e.argv=[],e.on=a,e.addListener=a,e.once=a,e.off=a,e.removeListener=a,e.removeAllListeners=a,e.emit=a,e.binding=function(e){throw new Error(\"process.binding is not supported\")},e.cwd=function(){return\"/\"},e.chdir=function(e){throw new Error(\"process.chdir is not supported\")}}.call(this,e(\"lYpoI2\"),\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:{},e(\"buffer\").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],\"/node_modules/gulp-browserify/node_modules/process/browser.js\",\"/node_modules/gulp-browserify/node_modules/process\")},{buffer:3,lYpoI2:11}]},{},[1])(1)});","import hash from \"object-hash\";\nimport { GeoPoint } from \"@rebasepro/types\";\n\n/** @private is the value an empty array? */\nexport const isEmptyArray = (value?: unknown) =>\n Array.isArray(value) && value.length === 0;\n\n/** @private is the given object a Function? */\nexport const isFunction = (obj: unknown): obj is (...args: unknown[]) => unknown =>\n typeof obj === \"function\";\n\n/** @private is the given object an integer? */\nexport const isInteger = (obj: unknown): boolean =>\n String(Math.floor(Number(obj))) === String(obj);\n\n/** @private is the given object a NaN? */\n\nexport const isNaN = (obj: unknown): boolean => obj !== obj;\n\n/**\n * Deeply get a value from an object via its path.\n */\nexport function getIn(\n obj: Record<string, unknown> | unknown[] | unknown,\n key: string | string[],\n def?: unknown,\n p = 0\n) {\n const path = toPath(key);\n while (obj && p < path.length) {\n obj = (obj as Record<string, unknown>)[path[p++]];\n }\n\n // check if path is not in the end\n if (p !== path.length && !obj) {\n return def;\n }\n\n return obj === undefined ? def : obj;\n}\n\nexport function setIn<T>(obj: T, path: string, value: unknown): T {\n const res = clone(obj) as Record<string, unknown>;\n let resVal: Record<string, unknown> = res;\n let i = 0;\n const pathArray = toPath(path);\n\n for (; i < pathArray.length - 1; i++) {\n const currentPath: string = pathArray[i];\n const currentObj = getIn(obj as Record<string, unknown>, pathArray.slice(0, i + 1));\n\n if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {\n resVal = resVal[currentPath] = clone(currentObj) as Record<string, unknown>;\n } else {\n const nextPath: string = pathArray[i + 1];\n resVal = resVal[currentPath] =\n (isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {}) as Record<string, unknown>;\n }\n }\n\n // Return original object if new value is the same as current\n if ((i === 0 ? obj as Record<string, unknown> : resVal)[pathArray[i]] === value) {\n return obj;\n }\n\n if (value === undefined) {\n delete resVal[pathArray[i]];\n } else {\n resVal[pathArray[i]] = value;\n }\n\n // If the path array has a single element, the loop did not run.\n // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.\n if (i === 0 && value === undefined) {\n delete res[pathArray[i]];\n }\n\n return res as T;\n}\n\nexport function clone<T>(value: T): T {\n if (Array.isArray(value)) {\n return [...value] as T;\n } else if (typeof value === \"object\" && value !== null) {\n return { ...value } as T;\n } else {\n return value; // This is for primitive types which do not need cloning.\n }\n}\n\n/**\n * Deep clone a value, preserving function references and class instances.\n * Unlike structuredClone, this handles objects that contain functions\n * (e.g. EntityCollection with target(), childCollections(), callbacks).\n */\nexport function deepClone<T>(value: T): T {\n if (value === null || value === undefined) return value;\n if (typeof value === \"function\") return value;\n if (typeof value !== \"object\") return value;\n\n if (Array.isArray(value)) {\n return value.map(item => deepClone(item)) as T;\n }\n\n // Preserve class instances (Date, GeoPoint, etc.) — don't recurse\n if (Object.getPrototypeOf(value) !== Object.prototype) {\n return value;\n }\n\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(value)) {\n result[key] = deepClone((value as Record<string, unknown>)[key]);\n }\n return result as T;\n}\n\nfunction toPath(value: string | string[]) {\n if (Array.isArray(value)) return value; // Already in path array form.\n // Replace brackets with dots, remove leading/trailing dots, then split by dot.\n return value.replace(/\\[(\\d+)]/g, \".$1\").replace(/^\\./, \"\").replace(/\\.$/, \"\").split(\".\");\n}\n\n\nexport const pick: <T extends Record<string, unknown>>(obj: T, ...args: (keyof T)[]) => Partial<T> = <T extends Record<string, unknown>>(obj: T, ...args: (keyof T)[]) => ({\n ...args.reduce<Record<string, unknown>>((res, key) => ({\n ...res,\n [key as string]: obj[key as string]\n }), {})\n}) as Partial<T>;\n\nexport function isObject(item: unknown): item is Record<string, unknown> {\n return !!item && typeof item === \"object\" && !Array.isArray(item);\n}\n\nexport function isPlainObject(obj: unknown): obj is Record<string, unknown> {\n // 1. Rule out non-objects, null, and arrays\n if (typeof obj !== \"object\" || obj === null || Array.isArray(obj)) {\n return false;\n }\n\n // 2. Get the object's direct prototype\n const proto = Object.getPrototypeOf(obj);\n\n // 3. A plain object's direct prototype is Object.prototype\n return proto === Object.prototype;\n}\n\nexport function mergeDeep<T extends object, U extends object>(\n target: T,\n source: U,\n ignoreUndefined = false\n): T & U {\n // If target is not a true object (e.g., null, array, primitive), return target itself.\n if (!isObject(target)) {\n return target as T & U;\n }\n\n // Create a shallow copy of the target to avoid modifying the original object.\n const output = { ...target };\n\n // If source is not a true object, there's nothing to merge from it.\n // Return the shallow copy of target.\n if (!isObject(source)) {\n return output as T & U;\n }\n\n // Iterate over keys in the source object.\n for (const key in source) {\n if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") {\n continue;\n }\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const outputValue = (output as Record<string, unknown>)[key]; // Current value in our merged object (originating from target)\n\n // Skip if source value is undefined and ignoreUndefined is true.\n // This handles both not adding new undefined properties and not overwriting existing properties with undefined.\n if (ignoreUndefined && sourceValue === undefined) {\n continue;\n }\n\n if (sourceValue instanceof Date) {\n // If source value is a Date, create a new Date instance.\n (output as Record<string, unknown>)[key] = new Date(sourceValue.getTime());\n } else if (Array.isArray(sourceValue)) {\n if (Array.isArray(outputValue)) {\n // If the array contains primitives or class instances (non-plain objects),\n // overwrite the array entirely instead of doing element-wise merging.\n const hasPlainObjects = sourceValue.some(isPlainObject) || outputValue.some(isPlainObject);\n if (!hasPlainObjects) {\n (output as Record<string, unknown>)[key] = [...sourceValue];\n } else {\n const newArray = [];\n const maxLength = Math.max(outputValue.length, sourceValue.length);\n for (let i = 0; i < maxLength; i++) {\n const sourceItem = sourceValue[i];\n const targetItem = outputValue[i];\n\n if (i >= sourceValue.length) { // source is shorter\n newArray[i] = targetItem;\n } else if (i >= outputValue.length) { // target is shorter\n newArray[i] = sourceItem;\n } else if (sourceItem === null) {\n newArray[i] = targetItem;\n } else if (isPlainObject(sourceItem) && isPlainObject(targetItem)) {\n // Only recursively merge plain objects, preserve class instances\n newArray[i] = mergeDeep(targetItem, sourceItem, ignoreUndefined);\n } else {\n // For class instances and primitives, use source directly\n newArray[i] = sourceItem;\n }\n }\n (output as Record<string, unknown>)[key] = newArray;\n }\n } else {\n // If output's value (from target) is not an array,\n // overwrite with a shallow copy of the source array.\n (output as Record<string, unknown>)[key] = [...sourceValue];\n }\n } else if (isPlainObject(sourceValue)) {\n // If source value is a plain object (not a class instance like EntityReference, GeoPoint, etc.):\n if (isPlainObject(outputValue)) {\n // If the corresponding value in output (from target) is also a plain object, recurse.\n // Ensure the ignoreUndefined flag is passed down.\n (output as Record<string, unknown>)[key] = mergeDeep(outputValue as Record<string, unknown>, sourceValue, ignoreUndefined);\n } else {\n // If output's value (from target) is not a plain object (e.g., null, primitive, class instance, or key didn't exist in original target),\n // overwrite with the source object.\n (output as Record<string, unknown>)[key] = sourceValue;\n }\n } else if (isObject(sourceValue)) {\n // If source value is a class instance (not a plain object), use it directly to preserve prototype\n (output as Record<string, unknown>)[key] = sourceValue;\n } else {\n // If source value is a primitive, null, or undefined (and not ignored).\n (output as Record<string, unknown>)[key] = sourceValue;\n }\n }\n }\n\n return output as T & U;\n}\n\nexport function getValueInPath(o: object | undefined, path: string): unknown {\n if (!o) return undefined;\n if (typeof o === \"object\") {\n if (path in o) {\n return (o as Record<string, unknown>)[path];\n }\n if (path.includes(\".\") || path.includes(\"[\")) {\n let pathSegments = path.split(/[.[]/);\n if (path.includes(\"[\")) {\n pathSegments = pathSegments.map(segment => segment.replace(\"]\", \"\"));\n }\n const firstSegment = pathSegments[0];\n const isArrayAndIndexExists = Array.isArray((o as Record<string, unknown>)[firstSegment]) && !isNaN(parseInt(pathSegments[1]));\n const nextObject = isArrayAndIndexExists\n ? ((o as Record<string, unknown>)[firstSegment] as unknown[])[parseInt(pathSegments[1])]\n : (o as Record<string, unknown>)[firstSegment];\n\n const nextPath = pathSegments.slice(isArrayAndIndexExists ? 2 : 1).join(\".\");\n if (nextPath === \"\")\n return nextObject;\n return getValueInPath(nextObject as object | undefined, nextPath);\n }\n }\n return undefined;\n}\n\nexport function removeInPath(o: object, path: string): object | undefined {\n const res = clone(o) as Record<string, unknown>;\n let current = res;\n const parts = path.split(\".\");\n const last = parts.pop();\n for (const part of parts) {\n if (part in current && current[part] !== null && typeof current[part] === \"object\") {\n current[part] = clone(current[part]) as Record<string, unknown>;\n current = current[part] as Record<string, unknown>;\n } else {\n return res;\n }\n }\n if (last && current && typeof current === \"object\") {\n delete current[last];\n }\n return res;\n}\n\nexport function removeFunctions(o: unknown): unknown {\n if (o === undefined) return undefined;\n if (o === null) return null;\n if (typeof o === \"object\") {\n // Handle arrays first - map over them recursively\n if (Array.isArray(o)) {\n return o.map(v => removeFunctions(v));\n }\n // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them\n if (!isPlainObject(o)) {\n return o;\n }\n return Object.entries(o)\n .filter(([_, value]) => typeof value !== \"function\")\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return { [key]: value.map(v => removeFunctions(v)) };\n } else if (typeof value === \"object\") {\n return { [key]: removeFunctions(value) };\n } else return { [key]: value };\n })\n .reduce((a, b) => ({ ...a,\n...b }), {});\n }\n return o;\n}\n\nexport function getHashValue<T>(v: T): string | null {\n if (!v) return null;\n if (typeof v === \"object\" && v !== null) {\n if (\"id\" in v)\n return String((v as Record<string, unknown>).id);\n else if (v instanceof Date)\n return v.toLocaleString();\n else if (v instanceof GeoPoint)\n return hash(v as Record<string, unknown>);\n }\n return hash(v as object, { ignoreUnknown: true });\n}\n\nexport function removeUndefined(value: unknown, removeEmptyStrings?: boolean): unknown {\n if (typeof value === \"function\") {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((v: unknown) => removeUndefined(v, removeEmptyStrings));\n }\n if (typeof value === \"object\") {\n if (value === null)\n return value;\n // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them\n if (!isPlainObject(value)) {\n return value;\n }\n const res: Record<string, unknown> = {};\n Object.keys(value).forEach((key) => {\n if (!isEmptyObject(value as object)) {\n const childRes = removeUndefined((value as Record<string, unknown>)[key], removeEmptyStrings);\n const isString = typeof childRes === \"string\";\n const shouldKeepIfString = !removeEmptyStrings || (removeEmptyStrings && !isString) || (removeEmptyStrings && isString && childRes !== \"\");\n if (childRes !== undefined && !isEmptyObject(childRes as object) && shouldKeepIfString)\n res[key] = childRes;\n }\n });\n return res;\n }\n return value;\n}\n\nexport function removeNulls(value: unknown): unknown {\n if (typeof value === \"function\") {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((v: unknown) => removeNulls(v));\n }\n if (typeof value === \"object\") {\n if (value === null)\n return value;\n // Preserve class instances (EntityReference, GeoPoint, etc.) - don't recurse into them\n if (!isPlainObject(value)) {\n return value;\n }\n const res: Record<string, unknown> = {};\n const obj = value as Record<string, unknown>;\n Object.keys(obj).forEach((key) => {\n if (obj[key] !== null)\n res[key] = removeNulls(obj[key]);\n });\n return res;\n }\n return value;\n}\n\nexport function isEmptyObject(obj: object) {\n return obj &&\n Object.getPrototypeOf(obj) === Object.prototype &&\n Object.keys(obj).length === 0\n}\n\nexport function removePropsIfExisting(source: Record<string, unknown> | unknown[], comparison: Record<string, unknown> | unknown[]) {\n const isObject = (val: unknown): val is Record<string, unknown> => typeof val === \"object\" && val !== null;\n const isArray = (val: unknown): val is unknown[] => Array.isArray(val);\n\n if (!isObject(source) || !isObject(comparison)) {\n return source;\n }\n\n const res = isArray(source) ? [...source] : { ...source };\n\n if (isArray(res)) {\n for (let i = res.length - 1; i >= 0; i--) {\n if (res[i] === comparison[i]) {\n res.splice(i, 1);\n } else if (isObject(res[i]) && isObject(comparison[i])) {\n res[i] = removePropsIfExisting(res[i] as unknown as Record<string, unknown>, (comparison as unknown as unknown[])[i] as Record<string, unknown>);\n }\n }\n } else {\n Object.keys(comparison).forEach(key => {\n if (key in res) {\n if (isObject(res[key]) && isObject(comparison[key])) {\n res[key] = removePropsIfExisting(res[key], comparison[key]);\n } else if (res[key] === comparison[key]) {\n delete res[key];\n }\n }\n });\n }\n\n return res;\n}\n","import { toSnakeCase } from \"./strings\";\n\n/**\n * Generates a foreign key column name from a given string, typically a collection slug or name.\n * It converts the name to snake_case, attempts to singularize it by removing a trailing 's'\n * (a common convention for collection names), and appends '_id'.\n *\n * @param name The base name to convert to a foreign key.\n * @returns A foreign key name in the format 'singular_name_id'.\n *\n * @example\n * // returns \"user_id\"\n * generateForeignKeyName(\"users\")\n *\n * @example\n * // returns \"post_id\"\n * generateForeignKeyName(\"posts\")\n *\n * @example\n * // returns \"product_id\"\n * generateForeignKeyName(\"Product\")\n *\n */\nexport function generateForeignKeyName(name: string): string {\n const snakeCaseName = toSnakeCase(name);\n // A simple heuristic to singularize a plural name, which is a common convention.\n const singularName = snakeCaseName.endsWith(\"s\") ? snakeCaseName.slice(0, -1) : snakeCaseName;\n return `${singularName}_id`;\n}\n\n","import {\n DataType,\n Entity,\n EntityReference,\n EntityRelation,\n EntityStatus,\n EntityValues,\n Properties,\n Property\n} from \"@rebasepro/types\";\nimport { DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE } from \"./common\";\nimport { mergeDeep } from \"@rebasepro/utils\";\n\nexport function isReadOnly(property: Property): boolean {\n if (property.ui?.readOnly)\n return true;\n if (property.type === \"date\") {\n if (property.autoValue)\n return true;\n }\n if (property.type === \"reference\") {\n return !property.path && !(\"Field\" in (property.ui || {}) && property.ui?.Field);\n }\n return false;\n}\n\nexport function isHidden(property: Property): boolean {\n return typeof property.ui?.disabled === \"object\" && Boolean(property.ui?.disabled.hidden);\n}\n\nexport function isPropertyBuilder(property?: Property) {\n return typeof property?.dynamicProps === \"function\";\n}\n\nexport function getDefaultValuesFor<M extends Record<string, unknown>>(properties: Properties): Partial<EntityValues<M>> {\n if (!properties) return {};\n return Object.entries(properties)\n .map(([key, property]) => {\n if (!property) return {};\n const value = getDefaultValueFor(property);\n return value === undefined ? {} : { [key]: value };\n })\n .reduce((a, b) => ({ ...a,\n...b }), {}) as EntityValues<M>;\n}\n\nexport function getDefaultValueFor(property?: Property): unknown {\n if (!property) return undefined;\n if (isPropertyBuilder(property)) return undefined;\n if (property.defaultValue || property.defaultValue === null) {\n return property.defaultValue;\n } else if (property.type === \"map\" && property.properties) {\n const defaultValuesFor = getDefaultValuesFor(property.properties as Properties);\n if (Object.keys(defaultValuesFor).length === 0) return undefined;\n return defaultValuesFor;\n } else {\n return getDefaultValueFortype(property.type);\n }\n}\n\nexport function getDefaultValueFortype(type: DataType): unknown {\n if (type === \"string\") {\n return null;\n } else if (type === \"number\") {\n return null;\n } else if (type === \"boolean\") {\n return false;\n } else if (type === \"date\") {\n return null;\n } else if (type === \"array\") {\n return [];\n } else if (type === \"map\") {\n return {};\n } else if (type === \"vector\") {\n return null;\n } else if (type === \"binary\") {\n return null;\n } else {\n return null;\n }\n}\n\n/**\n * Update the automatic values in an entity before save\n * @group Driver\n */\nexport function updateDateAutoValues<M extends Record<string, unknown>>({\n inputValues,\n properties,\n status,\n timestampNowValue\n}:\n {\n inputValues: Partial<EntityValues<M>>,\n properties: Properties,\n status: EntityStatus,\n timestampNowValue: unknown\n }): EntityValues<M> {\n return traverseValuesProperties(\n inputValues,\n properties,\n (inputValue, property) => {\n if (property.type === \"date\") {\n if (status === \"existing\" && property.autoValue === \"on_update\") {\n return timestampNowValue;\n } else if ((status === \"new\" || status === \"copy\") &&\n (property.autoValue === \"on_update\" || property.autoValue === \"on_create\")) {\n return timestampNowValue;\n } else {\n return inputValue;\n }\n } else {\n return inputValue;\n }\n }\n ) ?? {} as M;\n}\n\n/**\n * Add missing required fields, expected in the collection, to the values of an entity\n * @param values\n * @param properties\n * @group Driver\n */\nexport function sanitizeData<M extends Record<string, unknown>>\n (\n values: EntityValues<M>,\n properties: Properties\n ) {\n const result = values as Record<string, unknown>;\n Object.entries(properties)\n .forEach(([key, property]) => {\n if (values && values[key] !== undefined) result[key] = values[key];\n else if ((property as Property).validation?.required) result[key] = null;\n });\n return result;\n}\n\nexport function getReferenceFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityReference {\n if (typeof entity.id !== \"string\")\n throw new Error(\"Only string IDs are supported in references\");\n return new EntityReference({\n id: entity.id,\n path: entity.path,\n driver: entity.driver,\n databaseId: entity.databaseId\n });\n}\n\nexport function getRelationFrom<M extends Record<string, unknown>>(entity: Entity<M>): EntityRelation {\n return new EntityRelation(entity.id, entity.path, entity);\n}\n\n/**\n * Normalize a value into a proper EntityRelation instance.\n * Handles EntityRelation class instances, and plain objects\n * with `__type === \"relation\"` or an `isEntityRelation()` method.\n *\n * When `propertyType` is `\"relation\"`, also accepts plain objects that\n * have `id` and `path` fields — these are relation-shaped objects from\n * edge cases in the data pipeline (REST fallback, stale cache, custom data source).\n *\n * Returns null if the value cannot be coerced.\n */\nexport function normalizeToEntityRelation(value: unknown, propertyType?: string): EntityRelation | null {\n if (value instanceof EntityRelation) return value;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n\n const obj = value as Record<string, unknown>;\n const isRelationLike =\n obj.__type === \"relation\" ||\n obj.__type === \"reference\" ||\n (typeof obj.isEntityRelation === \"function\" && (obj.isEntityRelation as () => boolean)()) ||\n (typeof obj.isEntityReference === \"function\" && (obj.isEntityReference as () => boolean)()) ||\n (propertyType === \"relation\" && typeof obj.id !== \"undefined\" && typeof obj.path === \"string\");\n\n if (!isRelationLike) return null;\n\n return new EntityRelation(\n obj.id as string | number,\n obj.path as string,\n obj.data as Entity | undefined\n );\n}\n\nexport function traverseValuesProperties<M extends Record<string, unknown>>(\n inputValues: Partial<EntityValues<M>>,\n properties: Properties,\n operation: (value: unknown, property: Property) => unknown\n): EntityValues<M> | undefined {\n // Handle null/undefined inputValues - use empty object as base for mergeDeep\n const safeInputValues = inputValues ?? {};\n\n const updatedValues = Object.entries(properties)\n .map(([key, property]) => {\n const inputValue = safeInputValues && (safeInputValues)[key];\n const updatedValue = traverseValueProperty(inputValue, property as Property, operation);\n if (updatedValue === null) return null;\n if (updatedValue === undefined) return undefined;\n return ({ [key]: updatedValue });\n })\n .reduce((a, b) => ({ ...a,\n...b }), {}) as EntityValues<M>;\n // Use mergeDeep to preserve class instances like EntityReference, GeoPoint\n const result = mergeDeep(safeInputValues, updatedValues);\n if (!result || Object.keys(result).length === 0) return undefined;\n return result;\n}\n\nexport function traverseValueProperty(inputValue: unknown,\n property: Property,\n operation: (value: unknown, property: Property) => unknown): unknown {\n\n let value;\n if (property.type === \"map\" && property.properties) {\n value = traverseValuesProperties(inputValue as Partial<Record<string, unknown>>, property.properties, operation);\n } else if (property.type === \"array\") {\n const of = property.of;\n if (of && Array.isArray(inputValue) && !Array.isArray(of)) {\n value = inputValue.map((e) => traverseValueProperty(e, of, operation));\n } else if (of && Array.isArray(inputValue) && Array.isArray(of)) {\n value = inputValue.map((e, i) => {\n if (i < of.length)\n return traverseValueProperty(e, of[i], operation);\n return null\n }).filter(Boolean);\n } else if (property.oneOf && Array.isArray(inputValue)) {\n const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;\n const valueField = property.oneOf?.valueField ?? DEFAULT_ONE_OF_VALUE;\n value = inputValue.map((e) => {\n if (e === null) return null;\n if (typeof e !== \"object\") return e;\n const rec = e as Record<string, unknown>;\n const type = rec[typeField] as string;\n const childProperty = property.oneOf?.properties[type];\n if (!type || !childProperty) return e;\n return {\n [typeField]: type,\n [valueField]: traverseValueProperty(rec[valueField], childProperty, operation)\n };\n });\n } else {\n value = inputValue;\n }\n } else {\n value = operation(inputValue, property);\n }\n\n return value;\n}\n\n/**\n * Relation reference types used throughout the server layer.\n * These replace the 50+ manual `{ id, path, __type: \"relation\" }` constructions.\n */\nexport interface RelationRef {\n readonly id: string | number;\n readonly path: string;\n readonly __type: \"relation\";\n}\n\nexport interface RelationRefWithData extends RelationRef {\n readonly data: Entity;\n}\n\n/**\n * Create a lightweight relation stub for CMS views.\n * Replaces inline `{ id, path, __type: \"relation\" }` object literals.\n */\nexport function createRelationRef(id: string | number, path: string): RelationRef {\n return { id,\npath,\n__type: \"relation\" };\n}\n\n/**\n * Create a hydrated relation reference that includes the full entity data.\n * Used when entity data has been pre-fetched (e.g., via batch loading or JOINs).\n */\nexport function createRelationRefWithData(id: string | number, path: string, data: Entity): RelationRefWithData {\n return { id,\npath,\n__type: \"relation\",\ndata };\n}\n","import { EnumValueConfig, EnumValues } from \"@rebasepro/types\";\n\nexport function enumToObjectEntries(enumValues: EnumValues): EnumValueConfig[] {\n if (Array.isArray(enumValues)) {\n return enumValues;\n } else {\n return Object.entries(enumValues).map(([id, value]) => {\n if (typeof value === \"string\") {\n return {\n id,\n label: value\n }\n } else {\n return {\n ...value,\n id\n }\n }\n });\n }\n}\n\nexport function getLabelOrConfigFrom(enumValues: EnumValueConfig[], key?: string | number): EnumValueConfig | undefined {\n if (key === null || key === undefined) return undefined;\n return enumValues.find((entry) => String(entry.id) === String(key));\n}\n","import { CollectionWithRelations, EntityCollection, getDataSourceCapabilities, Property, Relation, RelationProperty } from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { generateForeignKeyName } from \"@rebasepro/utils\";\n\nexport function sanitizeRelation(\n relation: Partial<Relation>,\n sourceCollection: EntityCollection,\n resolveCollection?: (slugOrTable: string) => EntityCollection | undefined\n): Relation {\n if (!relation.target) {\n throw new Error(\"Relation is missing a `target` collection.\");\n }\n\n const rawTarget = relation.target;\n let targetCollection: EntityCollection | undefined;\n\n if (typeof rawTarget === \"string\") {\n if (resolveCollection) {\n targetCollection = resolveCollection(rawTarget);\n }\n if (!targetCollection) {\n targetCollection = { slug: rawTarget,\nname: rawTarget } as EntityCollection;\n }\n } else if (typeof rawTarget === \"function\") {\n const evaluated = rawTarget();\n if (typeof evaluated === \"string\") {\n if (resolveCollection) {\n targetCollection = resolveCollection(evaluated);\n }\n if (!targetCollection) {\n targetCollection = { slug: evaluated,\nname: evaluated } as EntityCollection;\n }\n } else {\n targetCollection = evaluated;\n }\n } else if (rawTarget && typeof rawTarget === \"object\") {\n targetCollection = rawTarget as EntityCollection;\n }\n\n if (!targetCollection) {\n throw new Error(\"Relation is missing a valid `target` collection.\");\n }\n\n const newRelation: Partial<Relation> = { ...relation };\n\n newRelation.target = () => {\n if (typeof rawTarget === \"string\") {\n return (resolveCollection && resolveCollection(rawTarget)) || targetCollection!;\n } else if (typeof rawTarget === \"function\") {\n const evaluated = rawTarget();\n if (typeof evaluated === \"string\") {\n return (resolveCollection && resolveCollection(evaluated)) || targetCollection!;\n }\n return evaluated;\n }\n return targetCollection!;\n };\n\n // 1. Default relationName from target collection slug\n if (!newRelation.relationName) {\n newRelation.relationName = toSnakeCase(targetCollection.slug);\n }\n\n // 2. Infer or default direction if absent\n if (!newRelation.direction) {\n if (newRelation.foreignKeyOnTarget) newRelation.direction = \"inverse\";\n else if (newRelation.through) newRelation.direction = \"owning\";\n else if (newRelation.cardinality === \"many\") newRelation.direction = \"inverse\"; // Default has-many to be inverse\n else newRelation.direction = \"owning\"; // Default all others to owning\n }\n\n // Do not default keys if a custom joinPath is provided; it's an advanced override.\n if (!newRelation.joinPath) {\n const sourceName = toSnakeCase(sourceCollection.slug ?? sourceCollection.name);\n\n // 3. Default keys based on the relation type (cardinality and direction)\n if (newRelation.cardinality === \"one\" && newRelation.direction === \"owning\") {\n // Belongs-to / many-to-one\n if (!newRelation.localKey) {\n newRelation.localKey = generateForeignKeyName(newRelation.relationName);\n }\n } else if (newRelation.cardinality === \"one\" && newRelation.direction === \"inverse\") {\n // Inverse one-to-one: the foreign key is on the target table pointing back to this collection\n if (!newRelation.foreignKeyOnTarget) {\n // First, try to find the corresponding owning relation's localKey on the target collection\n let foundForeignKey = false;\n\n try {\n // Look for an owning relation on the target that points back to this collection\n const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? (((targetCollection as CollectionWithRelations).relations) || []) : [];\n for (const targetRel of targetRelations) {\n if (targetRel.direction === \"owning\" &&\n targetRel.cardinality === \"one\" &&\n targetRel.localKey) {\n try {\n const targetRelTarget = targetRel.target();\n if (targetRelTarget.slug === sourceCollection.slug) {\n // Found the corresponding owning relation, use its localKey\n newRelation.foreignKeyOnTarget = targetRel.localKey;\n foundForeignKey = true;\n break;\n }\n } catch (e) {\n // Continue looking if we can't resolve this target\n continue;\n }\n }\n }\n } catch (e) {\n // If we can't inspect the target collection, fall back to naming convention\n }\n\n // If we couldn't find an explicit foreign key, fall back to naming convention\n if (!foundForeignKey) {\n const keyPrefix = newRelation.inverseRelationName\n ? toSnakeCase(newRelation.inverseRelationName)\n : sourceName;\n newRelation.foreignKeyOnTarget = generateForeignKeyName(keyPrefix);\n }\n }\n } else if (newRelation.cardinality === \"many\" && newRelation.direction === \"inverse\") {\n // This could be either one-to-many or many-to-many inverse relation\n // We need to check if there's a corresponding owning many-to-many relation\n\n let isManyToManyInverse = false;\n\n // Try to determine if this is a many-to-many inverse relation\n if (newRelation.inverseRelationName && !newRelation.foreignKeyOnTarget) {\n try {\n // Look for a corresponding owning many-to-many relation on the target collection.\n // Note: we intentionally do NOT require `through` here because the raw (unsanitized)\n // relations won't have `through` populated yet — sanitizeRelation fills it in later.\n // `cardinality: \"many\" + direction: \"owning\"` is sufficient to identify owning M2M.\n\n // 1. Check the explicit relations[] array\n const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? (((targetCollection as CollectionWithRelations).relations) || []) : [];\n for (const targetRel of targetRelations) {\n if (targetRel.cardinality === \"many\" &&\n (targetRel.direction === \"owning\" || !targetRel.direction) &&\n (targetRel.relationName === newRelation.inverseRelationName)) {\n isManyToManyInverse = true;\n break;\n }\n }\n\n // 2. Also check the target's properties for inline relation definitions\n // (e.g. posts.properties.tags = { type: \"relation\", cardinality: \"many\", direction: \"owning\" })\n if (!isManyToManyInverse && targetCollection.properties) {\n for (const [propKey, prop] of Object.entries(targetCollection.properties)) {\n if ((prop as Property).type !== \"relation\") continue;\n const relProp = prop as RelationProperty;\n const relName = relProp.relationName || propKey;\n if (relName === newRelation.inverseRelationName &&\n relProp.cardinality === \"many\" &&\n (relProp.direction === \"owning\" || !relProp.direction)) {\n isManyToManyInverse = true;\n break;\n }\n }\n }\n } catch (e) {\n // If we can't inspect the target collection, assume one-to-many\n }\n }\n\n // Only add foreignKeyOnTarget for one-to-many inverse relations\n if (!isManyToManyInverse && !newRelation.foreignKeyOnTarget) {\n newRelation.foreignKeyOnTarget = generateForeignKeyName(sourceName);\n }\n } else if (newRelation.cardinality === \"many\" && newRelation.direction === \"owning\") {\n\n // Many-to-many via junction table\n const sourceTableName = getTableName(sourceCollection);\n const targetTableName = getTableName(targetCollection);\n\n newRelation.through = {\n table: newRelation.through?.table ?? [sourceTableName, targetTableName].sort().join(\"_\"),\n sourceColumn: newRelation.through?.sourceColumn ?? generateForeignKeyName(sourceName),\n targetColumn: newRelation.through?.targetColumn ?? generateForeignKeyName(newRelation.relationName)\n };\n }\n }\n\n // 4. Basic validation to catch configuration errors early\n if (newRelation.cardinality === \"one\" && newRelation.direction === \"owning\" && !newRelation.localKey && !newRelation.joinPath) {\n throw new Error(`Configuration Error in relation from '${sourceCollection.name}': An 'owning' one-to-one relation requires a 'localKey'. Check the relation config for '${newRelation.relationName}'`);\n }\n if (newRelation.cardinality === \"one\" && newRelation.direction === \"inverse\" && !newRelation.foreignKeyOnTarget && !newRelation.joinPath) {\n throw new Error(`Configuration Error in relation from '${sourceCollection.name}': An 'inverse' one-to-one relation requires a 'foreignKeyOnTarget'. Check the relation config for '${newRelation.relationName}'`);\n }\n if (newRelation.cardinality === \"many\" && newRelation.direction === \"inverse\" && !newRelation.foreignKeyOnTarget && !newRelation.joinPath && !newRelation.inverseRelationName) {\n throw new Error(`Configuration Error in relation from '${sourceCollection.name}': An 'inverse' one-to-many relation requires a 'foreignKeyOnTarget'. Check the relation config for '${newRelation.relationName}'`);\n }\n\n return newRelation as Relation;\n}\n\n/** WeakMap cache — same collection instance always yields the same relation map. */\nconst _resolvedRelationsCache = new WeakMap<EntityCollection, Record<string, Relation>>();\n\nexport function resolveCollectionRelations(\n collection: EntityCollection\n): Record<string, Relation> {\n const cached = _resolvedRelationsCache.get(collection);\n if (cached) return cached;\n\n if (!getDataSourceCapabilities(collection.driver).supportsRelations) return {};\n const relCollection = collection as CollectionWithRelations;\n const relations: Record<string, Relation> = {};\n\n // Track which explicit relationName values have been registered so that\n // property-based entries in section 2 don't re-add the same underlying relation\n // under a different key (e.g. explicit \"company\" + property \"company_id\").\n const registeredRelationNames = new Set<string>();\n\n // 1. Process explicit relations from the `relations` field.\n // Each relation is stored once under its canonical relationName key.\n if (relCollection.relations) {\n relCollection.relations.forEach((relation: Relation) => {\n try {\n const normalizedRelation = sanitizeRelation(relation, collection);\n const relationKey = normalizedRelation.relationName;\n if (relationKey) {\n relations[relationKey] = normalizedRelation;\n registeredRelationNames.add(relationKey);\n }\n } catch (e) {\n // Ignore incomplete or invalid relations (e.g. missing target during registry setup)\n }\n });\n }\n\n // 2. Process properties of type \"relation\".\n // Only adds an entry if:\n // (a) the property key itself is not already in the map, AND\n // (b) the underlying relation (by relationName) hasn't already been registered.\n // This prevents duplicate entries when a property key differs from the\n // explicit relation's relationName (e.g. property \"company_id\" referencing\n // explicit relation \"company\").\n if (collection.properties) {\n Object.entries(collection.properties).forEach(([propKey, prop]) => {\n const relation = resolvePropertyRelation({\n propertyKey: propKey,\n property: prop as Property,\n sourceCollection: collection\n });\n if (relation) {\n // Skip if the property key is already registered\n if (relations[propKey]) return;\n\n // We previously skipped if the underlying relation was already registered under\n // its canonical relationName in section 1. But we need to keep the property mapping\n // for EntityFetchService to hydrate the relation back to the correct property key.\n // Deduplication for Drizzle schema generation is handled in generate-drizzle-schema-logic.ts.\n\n if (!relation.relationName) {\n relation.relationName = propKey;\n }\n const normalizedRelation = sanitizeRelation(relation, collection);\n relations[propKey] = normalizedRelation;\n registeredRelationNames.add(normalizedRelation.relationName ?? propKey);\n }\n });\n }\n\n _resolvedRelationsCache.set(collection, relations);\n return relations;\n}\n\nexport function resolvePropertyRelation({\n propertyKey,\n property,\n sourceCollection\n}: {\n propertyKey: string;\n property: Property;\n sourceCollection: EntityCollection;\n}): Relation | undefined {\n if (property.type !== \"relation\") return undefined;\n\n const relProp = property as RelationProperty;\n\n // If the property has inline config (target set), build a Relation from it.\n // We only support the flat format where properties are directly on the RelationProperty.\n if (relProp.target) {\n return {\n relationName: relProp.relationName || propertyKey,\n target: relProp.target,\n cardinality: relProp.cardinality || \"one\",\n direction: relProp.direction || \"owning\",\n inverseRelationName: relProp.inverseRelationName,\n localKey: relProp.localKey,\n foreignKeyOnTarget: relProp.foreignKeyOnTarget,\n through: relProp.through,\n joinPath: relProp.joinPath,\n onUpdate: relProp.onUpdate,\n onDelete: relProp.onDelete,\n overrides: relProp.overrides\n } as Relation;\n }\n\n console.warn(`Unrecognized or missing relation target for property '${propertyKey}' in collection '${sourceCollection.slug}'`);\n return undefined;\n}\n\nexport function getTableName(collection: EntityCollection): string {\n if (getDataSourceCapabilities(collection.driver).supportsRelations) {\n return (collection as CollectionWithRelations).table ?? toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);\n }\n return toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);\n}\n\nexport function getTableVarName(tableName: string): string {\n return tableName.replace(/_([a-z])/g, (_, char) => char.toUpperCase());\n}\n\nexport function getEnumVarName(tableName: string, propName: string): string {\n const tableVar = getTableVarName(tableName);\n const propVar = propName.charAt(0).toUpperCase() + propName.slice(1);\n return `${tableVar}${propVar}`;\n}\n\nexport function getColumnName(fullColumn: string): string {\n return fullColumn.includes(\".\") ? fullColumn.split(\".\").pop()! : fullColumn;\n}\n\n/**\n * Look up a relation by key with forgiving normalization.\n *\n * `resolveCollectionRelations` stores each relation under a single canonical\n * key (no aliases). This helper tries the given key as-is, then falls back to\n * slug form (underscores → hyphens) and snake_case form (hyphens → underscores)\n * so that callers that receive a key from external input (URL path segments,\n * user-provided config, etc.) can still find the right entry.\n */\nexport function findRelation(\n resolvedRelations: Record<string, Relation>,\n key: string\n): Relation | undefined {\n // Exact match first\n if (resolvedRelations[key]) return resolvedRelations[key];\n\n // Try slug form (e.g. \"company_id\" → \"company-id\")\n const slugKey = key.replace(/_/g, \"-\");\n if (slugKey !== key && resolvedRelations[slugKey]) return resolvedRelations[slugKey];\n\n // Try snake_case form (e.g. \"company-id\" → \"company_id\")\n const snakeKey = key.replace(/-/g, \"_\");\n if (snakeKey !== key && resolvedRelations[snakeKey]) return resolvedRelations[snakeKey];\n\n return undefined;\n}\n","import {\n ArrayProperty,\n AuthController,\n CollectionWithRelations,\n CollectionWithSubcollections,\n EntityCollection,\n EnumValueConfig,\n EnumValues,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty,\n getDataSourceCapabilities\n} from \"@rebasepro/types\";\n\ntype PropertyConfig = { property: unknown; [key: string]: unknown };\nimport { isPropertyBuilder } from \"./entities\";\nimport { enumToObjectEntries } from \"./enums\";\nimport { DEFAULT_ONE_OF_TYPE } from \"./common\";\nimport { isDefaultFieldConfigId } from \"@rebasepro/utils\";\nimport { getIn, mergeDeep } from \"@rebasepro/utils\";\nimport { resolveCollectionRelations } from \"./relations\";\n\n/**\n * Resolve property builders, enums and arrays.\n */\n\nexport type ResolvePropertyProps<M extends Record<string, unknown> = Record<string, unknown>> = {\n property: Property\n propertyKey?: string,\n values?: Partial<M>,\n previousValues?: Partial<M>,\n path?: string,\n entityId?: string | number,\n index?: number,\n propertyConfigs?: Record<string, PropertyConfig>;\n ignoreMissingFields?: boolean;\n authController: AuthController;\n}\n\nexport function resolveProperty<M extends Record<string, unknown> = Record<string, unknown>>(props: ResolvePropertyProps<M>): Property | null {\n\n const {\n property,\n ignoreMissingFields = false,\n ...rest\n } = props;\n\n let resultProperty: Property;\n\n if (isPropertyBuilder(property)) {\n const path = rest.path;\n if (!path) {\n // When path is not available (e.g. in preview contexts), skip dynamic\n // resolution and use the property as-is without dynamic modifications.\n resultProperty = property as Property;\n } else {\n const usedPropertyValue = rest.propertyKey ? getIn(rest.values, rest.propertyKey) : undefined;\n const dynamicProps = property.dynamicProps?.({\n ...rest,\n path,\n propertyValue: usedPropertyValue,\n values: rest.values ?? {},\n previousValues: rest.previousValues ?? rest.values ?? {}\n });\n resultProperty = mergeDeep(property, dynamicProps ?? {});\n }\n } else {\n resultProperty = property as Property;\n }\n\n // Apply dynamic properties if they exist\n if (resultProperty?.dynamicProps && rest.path) {\n const path = rest.path;\n const usedPropertyValue = rest.propertyKey ? getIn(rest.values, rest.propertyKey) : undefined;\n const dynamicPropsResult = resultProperty.dynamicProps({\n ...rest,\n path,\n propertyValue: usedPropertyValue,\n values: rest.values ?? {},\n previousValues: rest.previousValues ?? rest.values ?? {}\n });\n\n if (dynamicPropsResult) {\n resultProperty = mergeDeep(resultProperty, dynamicPropsResult);\n }\n }\n\n let resolvedProperty: Property | null;\n\n if (resultProperty?.type === \"map\" && resultProperty.properties) {\n const properties = resolveProperties({\n ignoreMissingFields,\n ...rest,\n properties: resultProperty.properties\n });\n resolvedProperty = {\n ...resultProperty,\n properties\n } as Property;\n } else if (resultProperty?.type === \"array\") {\n resolvedProperty = resultProperty;\n } else if ((resultProperty?.type === \"string\" || resultProperty?.type === \"number\") && resultProperty.enum) {\n resolvedProperty = resolvePropertyEnum(resultProperty);\n } else {\n resolvedProperty = resultProperty;\n }\n\n if (resolvedProperty?.propertyConfig && !isDefaultFieldConfigId(resolvedProperty.propertyConfig)) {\n const cmsFields = rest.propertyConfigs;\n if (!cmsFields && !ignoreMissingFields) {\n throw Error(`Trying to resolve a property with key '${resolvedProperty.propertyConfig}' that inherits from a custom property config but no custom property configs were provided. Use the property 'propertyConfigs' in your app config to provide them`);\n }\n const customField: PropertyConfig | undefined = cmsFields?.[resolvedProperty.propertyConfig];\n if (!customField) {\n console.warn(`Trying to resolve a property with key '${resolvedProperty.propertyConfig}' that inherits from a custom property config but no custom property config with that key was found. Check the 'propertyConfigs' in your app config`)\n return resolvedProperty;\n }\n if (customField.property) {\n const restConfigProperty = { ...customField.property } as Record<string, unknown>;\n delete restConfigProperty.propertyConfig;\n const customFieldProperty = resolveProperty({\n property: { name: \"\",\n...restConfigProperty } as Property,\n ignoreMissingFields,\n ...rest\n });\n if (customFieldProperty) {\n resolvedProperty = mergeDeep(customFieldProperty, resolvedProperty);\n }\n }\n\n }\n\n return resolvedProperty;\n}\n\nexport function resolveRelationProperty(property: RelationProperty, relations: Relation[], propertyKey?: string) {\n // If the property already has a resolved relation, return as-is\n if (property.relation) {\n return property;\n }\n\n // Determine the relation name: explicit > property key\n const name = property.relationName || propertyKey;\n\n // Find the relation by name (it may have been extracted from the property during normalization)\n const relation = name ? relations.find((rel) => rel.relationName === name) : undefined;\n if (!relation) {\n throw Error(`Relation ${name ?? \"(unnamed)\"} not found`);\n }\n return {\n ...property,\n relation: relation\n } as RelationProperty;\n\n}\n\n/**\n * Resolve enum aliases for a string or number property\n * @param property\n */\nexport function resolvePropertyEnum(property: StringProperty | NumberProperty): StringProperty | NumberProperty {\n if (typeof property.enum === \"object\") {\n return {\n ...property,\n enum: enumToObjectEntries(property.enum)?.filter((value) => value && (value.id || value.id === 0) && value.label) ?? []\n };\n }\n return property as StringProperty | NumberProperty;\n}\n\n/**\n * Resolve enums and arrays for properties\n * @param properties\n * @param value\n */\nexport function resolveProperties<M extends Record<string, unknown>>({\n propertyKey,\n properties,\n ignoreMissingFields,\n ...props\n}: {\n propertyKey?: string,\n properties: Properties,\n values?: Partial<M>,\n previousValues?: Partial<M>,\n path?: string,\n entityId?: string | number,\n index?: number,\n propertyConfigs?: Record<string, PropertyConfig>;\n ignoreMissingFields?: boolean;\n authController: AuthController;\n}): Properties {\n return Object.entries<Property>(properties as Record<string, Property>)\n .map(([key, property]) => {\n const childResolvedProperty = resolveProperty({\n propertyKey: propertyKey ? `${propertyKey}.${key}` : undefined,\n property: property,\n ignoreMissingFields,\n ...props\n });\n if (!childResolvedProperty) return {};\n return {\n [key]: childResolvedProperty\n };\n })\n .filter((a) => a !== null)\n .reduce((a, b) => ({ ...a,\n...b }), {}) as Properties;\n}\n\nexport function resolveArrayProperties<M>({\n propertyKey,\n property,\n ignoreMissingFields = false,\n ...props\n}: {\n propertyKey?: string,\n property: ArrayProperty,\n values?: Partial<M>,\n previousValues?: Partial<M>,\n path?: string,\n entityId?: string | number,\n index?: number,\n propertyConfigs?: Record<string, PropertyConfig>;\n ignoreMissingFields?: boolean;\n authController: AuthController;\n}): Property[] {\n const propertyValue = propertyKey ? getIn(props.values, propertyKey) : undefined;\n\n if (property.of) {\n if (Array.isArray(property.of)) {\n return property.of.map((p, index) => {\n return resolveProperty({\n propertyKey: `${propertyKey}.${index}`,\n property: p as Property,\n ignoreMissingFields,\n ...props,\n index\n });\n }) as Property[];\n } else {\n const of = property.of;\n const resolvedProperties = getArrayResolvedProperties({\n propertyValue,\n propertyKey,\n property,\n ignoreMissingFields,\n ...props\n });\n const {\n values,\n previousValues,\n ...rest\n } = props;\n const ofProperty = resolveProperty({ // we don't want to pass the values of the parent entity\n property: of,\n ignoreMissingFields,\n ...rest\n });\n if (!ofProperty && !ignoreMissingFields)\n throw Error(\"When using a property builder as the 'of' prop of an ArrayProperty, you must return a valid child property\")\n return resolvedProperties;\n }\n } else if (property.oneOf) {\n const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;\n const resolvedProperties: Property[] = Array.isArray(propertyValue)\n ? propertyValue.map((v, index) => {\n const type = v && v[typeField];\n const childProperty = property.oneOf?.properties[type];\n if (!type || !childProperty) return null;\n return resolveProperty({\n propertyKey: `${propertyKey}.${index}`,\n property: childProperty,\n ignoreMissingFields,\n ...props\n });\n }).filter(e => Boolean(e)) as Property[]\n : [];\n return resolvedProperties;\n } else if (!(\"Field\" in (property.ui || {}) && property.ui?.Field)) {\n throw Error(`The array property (${propertyKey}) needs to declare an 'of' or a 'oneOf' property, or provide a custom \\`Field\\` component`);\n } else {\n return [];\n }\n\n}\n\nexport function getArrayResolvedProperties({\n propertyKey,\n propertyValue,\n property,\n ...props\n}: {\n propertyValue: unknown,\n propertyKey?: string,\n property: ArrayProperty,\n ignoreMissingFields: boolean,\n values?: object;\n previousValues?: object;\n path?: string;\n entityId?: string | number;\n index?: number;\n propertyConfigs?: Record<string, PropertyConfig>;\n authController: AuthController;\n}) {\n\n const of = property.of;\n if (!of)\n throw Error(\n `Trying to resolve an array property (${propertyKey}) without providing an 'of' property`\n )\n return Array.isArray(propertyValue)\n ? propertyValue.map((v: unknown, index: number) => {\n return resolveProperty({\n propertyKey: `${propertyKey}.${index}`,\n property: Array.isArray(of) ? of[index] : of,\n ...props,\n index\n });\n }).filter(e => Boolean(e)) as Property[]\n : [];\n}\n\nexport function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {\n if (typeof input === \"object\") {\n return Object.entries(input).map(([id, value]) =>\n (typeof value === \"string\"\n ? {\n id,\n label: value\n }\n : value));\n } else if (Array.isArray(input)) {\n return input as EnumValueConfig[];\n } else {\n return undefined;\n }\n}\n\n\nexport function getSubcollections<M extends Record<string, unknown> = Record<string, unknown>>(collection: EntityCollection<M>): EntityCollection<Record<string, unknown>>[] {\n if (collection.childCollections) {\n return collection.childCollections() ?? [];\n }\n\n if (getDataSourceCapabilities(collection.driver).supportsSubcollections && (collection as CollectionWithSubcollections).subcollections) {\n return (collection as CollectionWithSubcollections).subcollections!() ?? [];\n }\n\n if (getDataSourceCapabilities(collection.driver).supportsRelations) {\n const resolvedRelations = resolveCollectionRelations(collection);\n const manyRelations = Object.values(resolvedRelations).filter((r: Relation) => r.cardinality === \"many\");\n\n return manyRelations.map((r: Relation) => {\n const target = r.target();\n if (!target) return undefined;\n const relationKey = r.relationName || target.slug;\n\n // Try to find corresponding property to get custom name\n let customName: string | undefined;\n if (collection.properties) {\n const prop = Object.entries(collection.properties as Record<string, Property>).find(\n ([_, p]) => p.type === \"relation\" && p.relationName === relationKey\n );\n if (prop && prop[1].name) {\n customName = prop[1].name;\n }\n }\n\n const baseOverrides: Partial<EntityCollection> = { slug: relationKey };\n if (customName) {\n baseOverrides.name = customName;\n baseOverrides.singularName = customName;\n }\n\n const targetWithOverrides = { ...target,\n...baseOverrides };\n return (r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides) as EntityCollection<Record<string, unknown>>;\n }).filter((c: EntityCollection<Record<string, unknown>> | undefined): c is EntityCollection<Record<string, unknown>> => Boolean(c));\n }\n\n return [];\n}\n","import { CollectionWithRelations, Entity, EntityCollection, getDataSourceCapabilities, SecurityRule, User } from \"@rebasepro/types\";\n\n/**\n * Minimal auth context for permission checking.\n * Only requires the user object — avoids forcing callers to construct\n * a full AuthController just to check permissions.\n */\nexport interface AuthContext<USER extends User = User> {\n user: USER | null;\n}\n\nfunction evaluateAST<USER extends User, M extends Record<string, unknown>>(sqlString: string, auth: AuthContext<USER>, entity: Entity<M> | null): boolean {\n // This is a client-side SQL evaluator used *only* for optimistic UI updates.\n // It parses basic AND / OR statements to evaluate RLS without backend roundtrips.\n if (!entity) return true;\n\n // 1. Clean outer parentheses\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 // 2. Split top-level OR / AND\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 return orParts.some(part => evaluateAST(part, auth, entity));\n }\n\n const andParts = splitByTopLevel(cleanedSQL, \" AND \");\n if (andParts.length > 1) {\n return andParts.every(part => evaluateAST(part, auth, entity));\n }\n\n const upperSQL = cleanedSQL.toUpperCase();\n\n // 3. Fallback for unparseable complex queries\n if (upperSQL.includes(\" IN \") || upperSQL.includes(\" EXISTS \")) {\n return true;\n }\n\n // 4. Role array checks\n // Pattern: `string_to_array(auth.roles(), ',') && ARRAY['admin', 'editor']`\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 = auth.user?.roles || [];\n return requiredRoles.some(r => userRoles.includes(r));\n }\n\n // Pattern: `string_to_array(auth.roles(), ',') @> ARRAY['admin']`\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 = auth.user?.roles || [];\n return requiredRoles.every(r => userRoles.includes(r));\n }\n\n // 5. Existing ID patterns\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 entity.values[match1[1]] === auth.user?.uid;\n }\n\n const match2 = cleanedSQL.match(pattern2);\n if (match2 && match2[1]) {\n return entity.values[match2[1]] === auth.user?.uid;\n }\n\n // 6. Simple equality\n // Pattern: `field = 'value'` or `{field} != 'value'`\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 const entityValue = entity.values[field];\n if (operator === \"=\") return entityValue === value;\n if (operator === \"!=\") return entityValue !== value;\n }\n\n return true; // Optimistic fallback for anything else\n}\n\nfunction evaluateRule<USER extends User, M extends Record<string, unknown>>(rule: SecurityRule, auth: AuthContext<USER>, entity: Entity<M> | null): boolean {\n\n if (rule.access === \"public\") return true;\n\n if (rule.ownerField) {\n if (!entity) {\n // null entity: optimistic — we can't evaluate ownership without data\n // Fall through to SQL checks below (if any). If none, will return true.\n } else {\n // Entity present: strictly check ownership. Fail immediately if mismatch.\n if (entity.values[rule.ownerField] !== auth.user?.uid) return false;\n }\n }\n\n // In PostgreSQL RLS, USING and WITH CHECK have distinct semantics:\n // USING applies to existing rows (SELECT/UPDATE/DELETE read phase)\n // WITH CHECK applies to new/modified values (INSERT/UPDATE write phase)\n // Both must pass. We evaluate both independently.\n if (rule.using && !evaluateAST(rule.using, auth, entity)) return false;\n if (rule.withCheck && !evaluateAST(rule.withCheck, auth, entity)) return false;\n\n return true;\n}\n\nexport function checkOperation<M extends Record<string, unknown>, USER extends User>(\n collection: EntityCollection<M>,\n authContext: AuthContext<USER>,\n entity: Entity<M> | null,\n targetOperation: \"select\" | \"insert\" | \"update\" | \"delete\"\n): boolean {\n const securityRules = getDataSourceCapabilities(collection.driver).supportsRLS ? (collection as CollectionWithRelations).securityRules : undefined;\n if (!securityRules || securityRules.length === 0) {\n return true;\n }\n\n const applicableRules = 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) return false;\n\n const userRoleIds = authContext.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) return false;\n\n let grantedByPermissive = false;\n let deniedByRestrictive = false;\n\n for (const rule of roleApplicableRules) {\n const mode = rule.mode || \"permissive\";\n const passed = evaluateRule(rule, authContext, entity);\n\n if (mode === \"restrictive\" && !passed) {\n deniedByRestrictive = true;\n break;\n }\n\n if (mode === \"permissive\" && passed) {\n grantedByPermissive = true;\n }\n }\n\n if (deniedByRestrictive) return false;\n\n const hasPermissive = roleApplicableRules.some((r: SecurityRule) => (r.mode || \"permissive\") === \"permissive\");\n if (hasPermissive) {\n return grantedByPermissive;\n } else {\n return false;\n }\n}\n\nexport function canReadCollection<M extends Record<string, unknown>, USER extends User>\n (\n collection: EntityCollection<M>,\n authContext: AuthContext<USER>\n ): boolean {\n return checkOperation(collection, authContext, null, \"select\");\n}\n\nexport function canEditEntity<M extends Record<string, unknown>, USER extends User>\n (\n collection: EntityCollection<M>,\n authContext: AuthContext<USER>,\n path: string,\n entity: Entity<M> | null\n ): boolean {\n return checkOperation(collection, authContext, entity, \"update\");\n}\n\nexport function canCreateEntity<M extends Record<string, unknown>, USER extends User>\n (\n collection: EntityCollection<M>,\n authContext: AuthContext<USER>,\n path: string,\n entity: Entity<M> | null\n ): boolean {\n return checkOperation(collection, authContext, entity, \"insert\");\n}\n\nexport function canDeleteEntity<M extends Record<string, unknown>, USER extends User>\n (\n collection: EntityCollection<M>,\n authContext: AuthContext<USER>,\n path: string,\n entity: Entity<M> | null\n ): boolean {\n return checkOperation(collection, authContext, entity, \"delete\");\n}\n","import { EntityCollection, EntityReference } from \"@rebasepro/types\";\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"./resolutions\";\n\nexport function getParentReferencesFromPath(props: {\n path: string,\n collections: EntityCollection[] | undefined,\n currentFullPath?: string,\n}): EntityReference[] {\n\n const {\n path,\n collections = [],\n currentFullPath\n } = props;\n\n const subpaths = removeInitialAndTrailingSlashes(path).split(\"/\");\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n\n const result: EntityReference[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection: EntityCollection | undefined = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n // If we find a collection, we add the reference and continue\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug) // Use the current full path if provided\n : collection.slug;\n\n const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, \"\"));\n const nextSegments = restOfThePath.length > 0 ? restOfThePath.split(\"/\") : [];\n if (nextSegments.length > 0) {\n const entityId = nextSegments[0];\n const path = collectionPath + \"/\" + entityId;\n result.push(new EntityReference({ id: entityId,\npath: collectionPath }));\n if (nextSegments.length > 1) {\n const newPath = nextSegments.slice(1).join(\"/\");\n if (!collection) {\n throw Error(\"collection not found resolving path: \" + collection);\n }\n if (getSubcollections(collection).length > 0) {\n result.push(...getParentReferencesFromPath({\n path: newPath,\n collections: getSubcollections(collection),\n currentFullPath: path\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n","import { EntityCallbacks, Properties } from \"@rebasepro/types\";\n\n/**\n * Helper function to recursively check if there are any callbacks in the properties.\n */\nfunction hasPropertyCallbacks(properties: Properties, callbackName: \"afterRead\" | \"beforeSave\"): boolean {\n if (!properties) return false;\n for (const property of Object.values(properties)) {\n if (property.callbacks?.[callbackName]) return true;\n if (property.type === \"map\" && property.properties) {\n if (hasPropertyCallbacks(property.properties, callbackName)) return true;\n } else if (property.type === \"array\" && property.of) {\n const ofs = Array.isArray(property.of) ? property.of : [property.of];\n for (const of of ofs) {\n if (of.callbacks?.[callbackName]) return true;\n if (of.type === \"map\" && of.properties && hasPropertyCallbacks(of.properties, callbackName)) return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Recursively process properties to apply field-level hooks.\n */\nasync function processProperties(\n properties: Properties,\n values: Record<string, unknown>,\n previousValues: Record<string, unknown>,\n propsContext: unknown,\n callbackName: \"afterRead\" | \"beforeSave\"\n): Promise<Record<string, unknown>> {\n if (!values || typeof values !== \"object\") return values;\n\n const result = { ...values };\n\n for (const [key, property] of Object.entries(properties)) {\n if (result[key] === undefined) continue;\n\n let currentValue = result[key];\n const previousValue = previousValues?.[key];\n\n // 1. Array Property\n if (property.type === \"array\" && Array.isArray(currentValue)) {\n // We only support traversing single-type arrays for hooks currently to avoid complex union matching\n if (property.of && !Array.isArray(property.of)) {\n currentValue = await Promise.all(currentValue.map(async (item, index) => {\n const prevItem = Array.isArray(previousValue) ? previousValue[index] : undefined;\n // Mock a properties object to process a single item\n const singlePropData = { \"_tmp\": property.of } as Properties;\n const res = await processProperties(singlePropData, { \"_tmp\": item }, { \"_tmp\": prevItem }, propsContext, callbackName);\n return res[\"_tmp\"];\n }));\n }\n }\n // 2. Map Property\n else if (property.type === \"map\" && property.properties && typeof currentValue === \"object\") {\n currentValue = await processProperties(property.properties, currentValue as Record<string, unknown>, (previousValue ?? {}) as Record<string, unknown>, propsContext, callbackName);\n }\n\n // 3. Property's own callback\n if (property.callbacks?.[callbackName]) {\n\n const cbRes = await Promise.resolve(property.callbacks[callbackName]({\n ...(propsContext as Record<string, unknown>),\n value: currentValue,\n previousValue\n } as never));\n if (cbRes !== undefined) {\n currentValue = cbRes;\n }\n }\n\n result[key] = currentValue;\n }\n return result;\n}\n\n/**\n * Helper function to extract field-level PropertyCallbacks from a properties schema\n * and wrap them into an EntityCallbacks object recursively.\n */\nexport const buildPropertyCallbacks = (properties: Properties): EntityCallbacks | undefined => {\n if (!properties) return undefined;\n\n const propertyCallbacks: EntityCallbacks = {};\n\n if (hasPropertyCallbacks(properties, \"afterRead\")) {\n propertyCallbacks.afterRead = async (props) => {\n const processedValues = await processProperties(\n properties,\n props.entity.values as Record<string, unknown>,\n props.entity.values as Record<string, unknown>,\n props as unknown,\n \"afterRead\"\n );\n return { ...props.entity,\nvalues: processedValues };\n };\n }\n\n if (hasPropertyCallbacks(properties, \"beforeSave\")) {\n propertyCallbacks.beforeSave = async (props) => {\n return await processProperties(\n properties,\n props.values as Record<string, unknown>,\n (props.previousValues ?? {}) as Record<string, unknown>,\n props as unknown,\n \"beforeSave\"\n );\n };\n }\n\n return Object.keys(propertyCallbacks).length > 0 ? propertyCallbacks : undefined;\n};\n","/* globals define,module */\n/*\nUsing a Universal Module Loader that should be browser, require, and AMD friendly\nhttp://ricostacruz.com/cheatsheets/umdjs.html\n*/\n;(function(root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define(factory);\n } else if (typeof exports === \"object\") {\n module.exports = factory();\n } else {\n root.jsonLogic = factory();\n }\n}(this, function() {\n \"use strict\";\n /* globals console:false */\n\n if ( ! Array.isArray) {\n Array.isArray = function(arg) {\n return Object.prototype.toString.call(arg) === \"[object Array]\";\n };\n }\n\n /**\n * Return an array that contains no duplicates (original not modified)\n * @param {array} array Original reference array\n * @return {array} New array with no duplicates\n */\n function arrayUnique(array) {\n var a = [];\n for (var i=0, l=array.length; i<l; i++) {\n if (a.indexOf(array[i]) === -1) {\n a.push(array[i]);\n }\n }\n return a;\n }\n\n var jsonLogic = {};\n var operations = {\n \"==\": function(a, b) {\n return a == b;\n },\n \"===\": function(a, b) {\n return a === b;\n },\n \"!=\": function(a, b) {\n return a != b;\n },\n \"!==\": function(a, b) {\n return a !== b;\n },\n \">\": function(a, b) {\n return a > b;\n },\n \">=\": function(a, b) {\n return a >= b;\n },\n \"<\": function(a, b, c) {\n return (c === undefined) ? a < b : (a < b) && (b < c);\n },\n \"<=\": function(a, b, c) {\n return (c === undefined) ? a <= b : (a <= b) && (b <= c);\n },\n \"!!\": function(a) {\n return jsonLogic.truthy(a);\n },\n \"!\": function(a) {\n return !jsonLogic.truthy(a);\n },\n \"%\": function(a, b) {\n return a % b;\n },\n \"log\": function(a) {\n console.log(a); return a;\n },\n \"in\": function(a, b) {\n if (!b || typeof b.indexOf === \"undefined\") return false;\n return (b.indexOf(a) !== -1);\n },\n \"cat\": function() {\n return Array.prototype.join.call(arguments, \"\");\n },\n \"substr\": function(source, start, end) {\n if (end < 0) {\n // JavaScript doesn't support negative end, this emulates PHP behavior\n var temp = String(source).substr(start);\n return temp.substr(0, temp.length + end);\n }\n return String(source).substr(start, end);\n },\n \"+\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return parseFloat(a, 10) + parseFloat(b, 10);\n }, 0);\n },\n \"*\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return parseFloat(a, 10) * parseFloat(b, 10);\n });\n },\n \"-\": function(a, b) {\n if (b === undefined) {\n return -a;\n } else {\n return a - b;\n }\n },\n \"/\": function(a, b) {\n return a / b;\n },\n \"min\": function() {\n return Math.min.apply(this, arguments);\n },\n \"max\": function() {\n return Math.max.apply(this, arguments);\n },\n \"merge\": function() {\n return Array.prototype.reduce.call(arguments, function(a, b) {\n return a.concat(b);\n }, []);\n },\n \"var\": function(a, b) {\n var not_found = (b === undefined) ? null : b;\n var data = this;\n if (typeof a === \"undefined\" || a===\"\" || a===null) {\n return data;\n }\n var sub_props = String(a).split(\".\");\n for (var i = 0; i < sub_props.length; i++) {\n if (data === null || data === undefined) {\n return not_found;\n }\n // Descending into data\n data = data[sub_props[i]];\n if (data === undefined) {\n return not_found;\n }\n }\n return data;\n },\n \"missing\": function() {\n /*\n Missing can receive many keys as many arguments, like {\"missing:[1,2]}\n Missing can also receive *one* argument that is an array of keys,\n which typically happens if it's actually acting on the output of another command\n (like 'if' or 'merge')\n */\n\n var missing = [];\n var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n var value = jsonLogic.apply({\"var\": key}, this);\n if (value === null || value === \"\") {\n missing.push(key);\n }\n }\n\n return missing;\n },\n \"missing_some\": function(need_count, options) {\n // missing_some takes two arguments, how many (minimum) items must be present, and an array of keys (just like 'missing') to check for presence.\n var are_missing = jsonLogic.apply({\"missing\": options}, this);\n\n if (options.length - are_missing.length >= need_count) {\n return [];\n } else {\n return are_missing;\n }\n },\n };\n\n jsonLogic.is_logic = function(logic) {\n return (\n typeof logic === \"object\" && // An object\n logic !== null && // but not null\n ! Array.isArray(logic) && // and not an array\n Object.keys(logic).length === 1 // with exactly one key\n );\n };\n\n /*\n This helper will defer to the JsonLogic spec as a tie-breaker when different language interpreters define different behavior for the truthiness of primitives. E.g., PHP considers empty arrays to be falsy, but Javascript considers them to be truthy. JsonLogic, as an ecosystem, needs one consistent answer.\n\n Spec and rationale here: http://jsonlogic.com/truthy\n */\n jsonLogic.truthy = function(value) {\n if (Array.isArray(value) && value.length === 0) {\n return false;\n }\n return !! value;\n };\n\n\n jsonLogic.get_operator = function(logic) {\n return Object.keys(logic)[0];\n };\n\n jsonLogic.get_values = function(logic) {\n return logic[jsonLogic.get_operator(logic)];\n };\n\n jsonLogic.apply = function(logic, data) {\n // Does this array contain logic? Only one way to find out.\n if (Array.isArray(logic)) {\n return logic.map(function(l) {\n return jsonLogic.apply(l, data);\n });\n }\n // You've recursed to a primitive, stop!\n if ( ! jsonLogic.is_logic(logic) ) {\n return logic;\n }\n\n var op = jsonLogic.get_operator(logic);\n var values = logic[op];\n var i;\n var current;\n var scopedLogic;\n var scopedData;\n var initial;\n\n // easy syntax for unary operators, like {\"var\" : \"x\"} instead of strict {\"var\" : [\"x\"]}\n if ( ! Array.isArray(values)) {\n values = [values];\n }\n\n // 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.\n if (op === \"if\" || op == \"?:\") {\n /* 'if' should be called with a odd number of parameters, 3 or greater\n This works on the pattern:\n if( 0 ){ 1 }else{ 2 };\n if( 0 ){ 1 }else if( 2 ){ 3 }else{ 4 };\n if( 0 ){ 1 }else if( 2 ){ 3 }else if( 4 ){ 5 }else{ 6 };\n\n The implementation is:\n For pairs of values (0,1 then 2,3 then 4,5 etc)\n If the first evaluates truthy, evaluate and return the second\n If the first evaluates falsy, jump to the next pair (e.g, 0,1 to 2,3)\n given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)\n given 0 parameters, return NULL (not great practice, but there was no Else)\n */\n for (i = 0; i < values.length - 1; i += 2) {\n if ( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) {\n return jsonLogic.apply(values[i+1], data);\n }\n }\n if (values.length === i+1) {\n return jsonLogic.apply(values[i], data);\n }\n return null;\n } else if (op === \"and\") { // Return first falsy, or last\n for (i=0; i < values.length; i+=1) {\n current = jsonLogic.apply(values[i], data);\n if ( ! jsonLogic.truthy(current)) {\n return current;\n }\n }\n return current; // Last\n } else if (op === \"or\") {// Return first truthy, or last\n for (i=0; i < values.length; i+=1) {\n current = jsonLogic.apply(values[i], data);\n if ( jsonLogic.truthy(current) ) {\n return current;\n }\n }\n return current; // Last\n } else if (op === \"filter\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n\n if ( ! Array.isArray(scopedData)) {\n return [];\n }\n // Return only the elements from the array in the first argument,\n // that return truthy when passed to the logic in the second argument.\n // For parity with JavaScript, reindex the returned array\n return scopedData.filter(function(datum) {\n return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum));\n });\n } else if (op === \"map\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n\n if ( ! Array.isArray(scopedData)) {\n return [];\n }\n\n return scopedData.map(function(datum) {\n return jsonLogic.apply(scopedLogic, datum);\n });\n } else if (op === \"reduce\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n initial = typeof values[2] !== \"undefined\" ? jsonLogic.apply(values[2], data) : null;\n\n if ( ! Array.isArray(scopedData)) {\n return initial;\n }\n\n return scopedData.reduce(\n function(accumulator, current) {\n return jsonLogic.apply(\n scopedLogic,\n {current: current, accumulator: accumulator}\n );\n },\n initial\n );\n } else if (op === \"all\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n // All of an empty set is false. Note, some and none have correct fallback after the for loop\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\n return false;\n }\n for (i=0; i < scopedData.length; i+=1) {\n if ( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\n return false; // First falsy, short circuit\n }\n }\n return true; // All were truthy\n } else if (op === \"none\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\n return true;\n }\n for (i=0; i < scopedData.length; i+=1) {\n if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\n return false; // First truthy, short circuit\n }\n }\n return true; // None were truthy\n } else if (op === \"some\") {\n scopedData = jsonLogic.apply(values[0], data);\n scopedLogic = values[1];\n\n if ( ! Array.isArray(scopedData) || ! scopedData.length) {\n return false;\n }\n for (i=0; i < scopedData.length; i+=1) {\n if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {\n return true; // First truthy, short circuit\n }\n }\n return false; // None were truthy\n }\n\n // Everyone else gets immediate depth-first recursion\n values = values.map(function(val) {\n return jsonLogic.apply(val, data);\n });\n\n\n // The operation is called with \"data\" bound to its \"this\" and \"values\" passed as arguments.\n // Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments\n if (operations.hasOwnProperty(op) && typeof operations[op] === \"function\") {\n return operations[op].apply(data, values);\n } else if (op.indexOf(\".\") > 0) { // Contains a dot, and not in the 0th position\n var sub_ops = String(op).split(\".\");\n var operation = operations;\n for (i = 0; i < sub_ops.length; i++) {\n if (!operation.hasOwnProperty(sub_ops[i])) {\n throw new Error(\"Unrecognized operation \" + op +\n \" (failed at \" + sub_ops.slice(0, i+1).join(\".\") + \")\");\n }\n // Descending into operations\n operation = operation[sub_ops[i]];\n }\n\n return operation.apply(data, values);\n }\n\n throw new Error(\"Unrecognized operation \" + op );\n };\n\n jsonLogic.uses_data = function(logic) {\n var collection = [];\n\n if (jsonLogic.is_logic(logic)) {\n var op = jsonLogic.get_operator(logic);\n var values = logic[op];\n\n if ( ! Array.isArray(values)) {\n values = [values];\n }\n\n if (op === \"var\") {\n // This doesn't cover the case where the arg to var is itself a rule.\n collection.push(values[0]);\n } else {\n // Recursion!\n values.forEach(function(val) {\n collection.push.apply(collection, jsonLogic.uses_data(val) );\n });\n }\n }\n\n return arrayUnique(collection);\n };\n\n jsonLogic.add_operation = function(name, code) {\n operations[name] = code;\n };\n\n jsonLogic.rm_operation = function(name) {\n delete operations[name];\n };\n\n jsonLogic.rule_like = function(rule, pattern) {\n // console.log(\"Is \". JSON.stringify(rule) . \" like \" . JSON.stringify(pattern) . \"?\");\n if (pattern === rule) {\n return true;\n } // TODO : Deep object equivalency?\n if (pattern === \"@\") {\n return true;\n } // Wildcard!\n if (pattern === \"number\") {\n return (typeof rule === \"number\");\n }\n if (pattern === \"string\") {\n return (typeof rule === \"string\");\n }\n if (pattern === \"array\") {\n // !logic test might be superfluous in JavaScript\n return Array.isArray(rule) && ! jsonLogic.is_logic(rule);\n }\n\n if (jsonLogic.is_logic(pattern)) {\n if (jsonLogic.is_logic(rule)) {\n var pattern_op = jsonLogic.get_operator(pattern);\n var rule_op = jsonLogic.get_operator(rule);\n\n if (pattern_op === \"@\" || pattern_op === rule_op) {\n // echo \"\\nOperators match, go deeper\\n\";\n return jsonLogic.rule_like(\n jsonLogic.get_values(rule, false),\n jsonLogic.get_values(pattern, false)\n );\n }\n }\n return false; // pattern is logic, rule isn't, can't be eq\n }\n\n if (Array.isArray(pattern)) {\n if (Array.isArray(rule)) {\n if (pattern.length !== rule.length) {\n return false;\n }\n /*\n Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)\n */\n for (var i = 0; i < pattern.length; i += 1) {\n // If any fail, we fail\n if ( ! jsonLogic.rule_like(rule[i], pattern[i])) {\n return false;\n }\n }\n return true; // If they *all* passed, we pass\n } else {\n return false; // Pattern is array, rule isn't\n }\n }\n\n // Not logic, not array, not a === match for rule.\n return false;\n };\n\n return jsonLogic;\n}));\n","import jsonLogic from \"json-logic-js\";\nimport {\n ArrayProperty,\n AuthController,\n ConditionContext,\n EnumValueConfig,\n JsonLogicRule,\n NumberProperty,\n PropertyConditions,\n Property,\n ReferenceProperty,\n StringProperty\n} from \"@rebasepro/types\";\n\n/**\n * Access a nested property from an object via dot notation.\n */\nfunction getIn(obj: Record<string, unknown> | unknown, path: string): unknown {\n if (!obj || !path) return undefined;\n return path.split(\".\").reduce((acc: unknown, part: string) => acc && (acc as Record<string, unknown>)[part], obj);\n}\n\nlet operationsRegistered = false;\n\n/**\n * Register custom JSON Logic operations for Rebase.\n * Call this once at app initialization.\n */\nexport function registerConditionOperations(): void {\n if (operationsRegistered) return;\n\n // Check if user has a specific role by ID\n jsonLogic.add_operation(\"hasRole\", function (this: ConditionContext, roleId: string) {\n return this?.user?.roles?.includes(roleId) ?? false;\n });\n\n // Check if user has any of the specified roles\n jsonLogic.add_operation(\"hasAnyRole\", function (this: ConditionContext, roleIds: string[]) {\n if (!this?.user?.roles || !Array.isArray(roleIds)) return false;\n return roleIds.some(role => this.user.roles.includes(role));\n });\n\n // Check if a timestamp is today\n jsonLogic.add_operation(\"isToday\", (timestamp: number) => {\n if (!timestamp) return false;\n const date = new Date(timestamp);\n const today = new Date();\n return date.getFullYear() === today.getFullYear() &&\n date.getMonth() === today.getMonth() &&\n date.getDate() === today.getDate();\n });\n\n // Check if a timestamp is in the past\n jsonLogic.add_operation(\"isPast\", (timestamp: number) => {\n if (!timestamp) return false;\n return timestamp < Date.now();\n });\n\n // Check if a timestamp is in the future\n jsonLogic.add_operation(\"isFuture\", (timestamp: number) => {\n if (!timestamp) return false;\n return timestamp > Date.now();\n });\n\n operationsRegistered = true;\n}\n\n/**\n * Evaluate a JSON Logic rule against the given context.\n */\nexport function evaluateCondition(rule: JsonLogicRule, context: ConditionContext): unknown {\n // Ensure operations are registered\n registerConditionOperations();\n return jsonLogic.apply(rule, context);\n}\n\n/**\n * Convert a value to a format suitable for JSON Logic evaluation.\n * Specifically handles Date objects by converting them to Unix timestamps.\n */\nfunction serializeValueForConditions(value: unknown): unknown {\n if (value === null || value === undefined) {\n return value;\n }\n\n // Handle Date objects\n if (value instanceof Date) {\n return value.getTime();\n }\n\n // Handle Firestore Timestamp-like objects (have toDate or toMillis)\n if (typeof (value as { toMillis?: () => number })?.toMillis === \"function\") {\n return (value as { toMillis: () => number }).toMillis();\n }\n if (typeof (value as { toDate?: () => Date })?.toDate === \"function\") {\n return (value as { toDate: () => Date }).toDate().getTime();\n }\n\n // Handle arrays recursively\n if (Array.isArray(value)) {\n return value.map(serializeValueForConditions);\n }\n\n // Handle plain objects recursively\n if (typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>)) {\n result[key] = serializeValueForConditions((value as Record<string, unknown>)[key]);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Build a ConditionContext from the current property resolution context.\n */\nexport function buildConditionContext(params: {\n propertyKey?: string;\n values?: Record<string, unknown>;\n previousValues?: Record<string, unknown>;\n path: string;\n entityId?: string;\n index?: number;\n authController: AuthController;\n}): ConditionContext {\n const {\n propertyKey,\n values,\n previousValues,\n path,\n entityId,\n index,\n authController\n } = params;\n\n const user = authController.user;\n const serializedValues = serializeValueForConditions(values ?? {});\n const serializedPreviousValues = serializeValueForConditions(previousValues ?? values ?? {});\n\n return {\n values: serializedValues as Record<string, unknown>,\n previousValues: serializedPreviousValues as Record<string, unknown>,\n propertyValue: propertyKey ? getIn(serializedValues, propertyKey) : undefined,\n path,\n entityId,\n isNew: !entityId,\n index,\n user: {\n uid: user?.uid ?? \"\",\n email: user?.email ?? null,\n displayName: user?.displayName ?? null,\n photoURL: user?.photoURL ?? null,\n roles: (user?.roles ?? []).map((r: unknown) => typeof r === \"string\" ? r : (r as { id: string }).id)\n },\n now: Date.now()\n };\n}\n\n/**\n * Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.\n */\nexport function applyPropertyConditions(\n property: Property,\n context: ConditionContext\n): Property {\n const { conditions } = property;\n if (!conditions) return property;\n\n const result = { ...property };\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIELD STATE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate disabled condition\n if (conditions.disabled) {\n const isDisabled = evaluateCondition(conditions.disabled, context);\n if (isDisabled) {\n result.ui = result.ui || {};\n result.ui.disabled = {\n clearOnDisabled: conditions.clearOnDisabled ?? false,\n disabledMessage: conditions.disabledMessage,\n hidden: false\n };\n }\n }\n\n // Evaluate hidden condition\n if (conditions.hidden) {\n const isHidden = evaluateCondition(conditions.hidden, context);\n if (isHidden) {\n result.ui = result.ui || {};\n result.ui.disabled = {\n ...(typeof result.ui?.disabled === \"object\" ? result.ui.disabled : {}),\n hidden: true,\n clearOnDisabled: conditions.clearOnDisabled ?? false\n };\n }\n }\n\n // Evaluate readOnly condition\n if (conditions.readOnly) {\n const isReadOnly = evaluateCondition(conditions.readOnly, context);\n if (isReadOnly) {\n result.ui = result.ui || {};\n result.ui.readOnly = true;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALIDATION CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Evaluate required condition\n if (conditions.required !== undefined) {\n const isRequired = evaluateCondition(conditions.required, context) as boolean;\n result.validation = {\n ...result.validation,\n required: isRequired as boolean | undefined,\n requiredMessage: conditions.requiredMessage\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // VALUE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n // Apply default value for new entities\n if (context.isNew && conditions.defaultValue !== undefined) {\n result.defaultValue = evaluateCondition(conditions.defaultValue, context) as Property[\"defaultValue\"];\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ENUM CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (\"enum\" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) {\n (result as Record<string, unknown>).enum = applyEnumConditions(\n result.enum as EnumValueConfig[],\n conditions,\n context\n );\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFERENCE CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"reference\") {\n if (conditions.referencePath) {\n (result as ReferenceProperty).path = evaluateCondition(conditions.referencePath, context) as string;\n }\n if (conditions.referenceFilter) {\n (result as ReferenceProperty).fixedFilter = evaluateCondition(conditions.referenceFilter, context) as ReferenceProperty[\"fixedFilter\"];\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // ARRAY CONDITIONS\n // ═══════════════════════════════════════════════════════════════════════\n\n if (result.type === \"array\") {\n if (conditions.canAddElements !== undefined) {\n (result as ArrayProperty).canAddElements = evaluateCondition(conditions.canAddElements, context) as boolean;\n }\n if (conditions.sortable !== undefined) {\n (result as ArrayProperty).sortable = evaluateCondition(conditions.sortable, context) as boolean;\n }\n }\n\n return result;\n}\n\n/**\n * Convert an object with numeric keys back to an array.\n * Firestore stores arrays as {\"0\": \"a\", \"1\": \"b\"} to avoid nested arrays.\n */\nfunction objectToArray(obj: unknown): string[] {\n if (Array.isArray(obj)) return obj.map(String);\n if (obj && typeof obj === \"object\") {\n const keys = Object.keys(obj);\n if (keys.length > 0 && keys.every(k => !isNaN(Number(k)))) {\n return keys\n .sort((a, b) => Number(a) - Number(b))\n .map(k => (obj as Record<string, unknown>)[k])\n .filter((v): v is string => typeof v === \"string\" || typeof v === \"number\")\n .map(String);\n }\n }\n return [];\n}\n\n/**\n * Apply enum-specific conditions to filter and modify enum values.\n */\nfunction applyEnumConditions(\n enumValues: EnumValueConfig[],\n conditions: PropertyConditions,\n context: ConditionContext\n): EnumValueConfig[] {\n let result = [...enumValues];\n\n // Apply allowedEnumValues filter\n if (conditions.allowedEnumValues) {\n const allowed = evaluateCondition(conditions.allowedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format (Firestore workaround)\n const allowedArray = objectToArray(allowed);\n if (allowedArray.length > 0) {\n result = result.filter(ev => allowedArray.includes(String(ev.id)));\n }\n }\n\n // Apply excludedEnumValues filter\n if (conditions.excludedEnumValues) {\n const excluded = evaluateCondition(conditions.excludedEnumValues, context);\n // Handle both array format and object-with-numeric-keys format\n const excludedArray = objectToArray(excluded);\n if (excludedArray.length > 0) {\n result = result.filter(ev => !excludedArray.includes(String(ev.id)));\n }\n }\n\n // Apply individual enum conditions\n if (conditions.enumConditions) {\n result = result\n .map(ev => {\n const evConditions = conditions.enumConditions?.[ev.id];\n if (!evConditions) return ev;\n\n // Check hidden condition first\n if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) {\n return null; // Will be filtered out\n }\n\n // Check disabled condition\n if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) {\n return {\n ...ev,\n disabled: true\n };\n }\n\n return ev;\n })\n .filter((ev): ev is EnumValueConfig => ev !== null);\n }\n\n return result;\n}\n","const { getOwnPropertyNames, getOwnPropertySymbols } = Object;\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst { hasOwnProperty } = Object.prototype;\n/**\n * Combine two comparators into a single comparators.\n */\nfunction combineComparators(comparatorA, comparatorB) {\n return function isEqual(a, b, state) {\n return comparatorA(a, b, state) && comparatorB(a, b, state);\n };\n}\n/**\n * Wrap the provided `areItemsEqual` method to manage the circular state, allowing\n * for circular references to be safely included in the comparison without creating\n * stack overflows.\n */\nfunction createIsCircular(areItemsEqual) {\n return function isCircular(a, b, state) {\n if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {\n return areItemsEqual(a, b, state);\n }\n const { cache } = state;\n const cachedA = cache.get(a);\n const cachedB = cache.get(b);\n if (cachedA && cachedB) {\n return cachedA === b && cachedB === a;\n }\n cache.set(a, b);\n cache.set(b, a);\n const result = areItemsEqual(a, b, state);\n cache.delete(a);\n cache.delete(b);\n return result;\n };\n}\n/**\n * Get the properties to strictly examine, which include both own properties that are\n * not enumerable and symbol properties.\n */\nfunction getStrictProperties(object) {\n return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));\n}\n/**\n * Whether the object contains the property passed as an own property.\n */\nconst hasOwn = \n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\nObject.hasOwn || ((object, property) => hasOwnProperty.call(object, property));\n\nconst PREACT_VNODE = '__v';\nconst PREACT_OWNER = '__o';\nconst REACT_OWNER = '_owner';\nconst { getOwnPropertyDescriptor, keys } = Object;\n/**\n * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevalue) basis.\n * Simplified, this maps to if the two values are referentially equal to one another (`a === b`) or both are `NaN`.\n *\n * @note\n * When available in the environment, this is just a re-export of the global\n * [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) method.\n */\nconst sameValueEqual = \n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\nObject.is\n || function sameValueEqual(a, b) {\n return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;\n };\n/**\n * Whether the values passed are equal based on a [SameValue](https://262.ecma-international.org/7.0/#sec-samevaluezero) basis.\n * Simplified, this maps to if the two values are referentially equal to one another (`a === b`), both are `NaN`, or both\n * are either positive or negative zero.\n */\nfunction sameValueZeroEqual(a, b) {\n return a === b || (a !== a && b !== b);\n}\n/**\n * Whether the values passed are equal based on a\n * [Strict Equality Comparison](https://262.ecma-international.org/7.0/#sec-strict-equality-comparison) basis.\n * Simplified, this maps to if the two values are referentially equal to one another (`a === b`).\n *\n * @note\n * This is mainly available as a convenience function, such as being a default when a function to determine equality between\n * two objects is used.\n */\nfunction strictEqual(a, b) {\n return a === b;\n}\n/**\n * Whether the array buffers are equal in value.\n */\nfunction areArrayBuffersEqual(a, b) {\n return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a), new Uint8Array(b));\n}\n/**\n * Whether the arrays are equal in value.\n */\nfunction areArraysEqual(a, b, state) {\n let index = a.length;\n if (b.length !== index) {\n return false;\n }\n while (index-- > 0) {\n if (!state.equals(a[index], b[index], index, index, a, b, state)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the dataviews are equal in value.\n */\nfunction areDataViewsEqual(a, b) {\n return (a.byteLength === b.byteLength\n && areTypedArraysEqual(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength)));\n}\n/**\n * Whether the dates passed are equal in value.\n */\nfunction areDatesEqual(a, b) {\n return sameValueEqual(a.getTime(), b.getTime());\n}\n/**\n * Whether the errors passed are equal in value.\n */\nfunction areErrorsEqual(a, b) {\n return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;\n}\n/**\n * Whether the `Map`s are equal in value.\n */\nfunction areMapsEqual(a, b, state) {\n const size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n const matchedIndices = new Array(size);\n const aIterable = a.entries();\n let aResult;\n let bResult;\n let index = 0;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n const bIterable = b.entries();\n let hasMatch = false;\n let matchIndex = 0;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (matchedIndices[matchIndex]) {\n matchIndex++;\n continue;\n }\n const aEntry = aResult.value;\n const bEntry = bResult.value;\n if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state)\n && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n index++;\n }\n return true;\n}\n/**\n * Whether the objects are equal in value.\n */\nfunction areObjectsEqual(a, b, state) {\n const properties = keys(a);\n let index = properties.length;\n if (keys(b).length !== index) {\n return false;\n }\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n if (!isPropertyEqual(a, b, state, properties[index])) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the objects are equal in value with strict property checking.\n */\nfunction areObjectsEqualStrict(a, b, state) {\n const properties = getStrictProperties(a);\n let index = properties.length;\n if (getStrictProperties(b).length !== index) {\n return false;\n }\n let property;\n let descriptorA;\n let descriptorB;\n // Decrementing `while` showed faster results than either incrementing or\n // decrementing `for` loop and than an incrementing `while` loop. Declarative\n // methods like `some` / `every` were not used to avoid incurring the garbage\n // cost of anonymous callbacks.\n while (index-- > 0) {\n property = properties[index];\n if (!isPropertyEqual(a, b, state, property)) {\n return false;\n }\n descriptorA = getOwnPropertyDescriptor(a, property);\n descriptorB = getOwnPropertyDescriptor(b, property);\n if ((descriptorA || descriptorB)\n && (!descriptorA\n || !descriptorB\n || descriptorA.configurable !== descriptorB.configurable\n || descriptorA.enumerable !== descriptorB.enumerable\n || descriptorA.writable !== descriptorB.writable)) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the primitive wrappers passed are equal in value.\n */\nfunction arePrimitiveWrappersEqual(a, b) {\n return sameValueEqual(a.valueOf(), b.valueOf());\n}\n/**\n * Whether the regexps passed are equal in value.\n */\nfunction areRegExpsEqual(a, b) {\n return a.source === b.source && a.flags === b.flags;\n}\n/**\n * Whether the `Set`s are equal in value.\n */\nfunction areSetsEqual(a, b, state) {\n const size = a.size;\n if (size !== b.size) {\n return false;\n }\n if (!size) {\n return true;\n }\n const matchedIndices = new Array(size);\n const aIterable = a.values();\n let aResult;\n let bResult;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while ((aResult = aIterable.next())) {\n if (aResult.done) {\n break;\n }\n const bIterable = b.values();\n let hasMatch = false;\n let matchIndex = 0;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while ((bResult = bIterable.next())) {\n if (bResult.done) {\n break;\n }\n if (!matchedIndices[matchIndex]\n && state.equals(aResult.value, bResult.value, aResult.value, bResult.value, a, b, state)) {\n hasMatch = matchedIndices[matchIndex] = true;\n break;\n }\n matchIndex++;\n }\n if (!hasMatch) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the TypedArray instances are equal in value.\n */\nfunction areTypedArraysEqual(a, b) {\n let index = a.byteLength;\n if (b.byteLength !== index || a.byteOffset !== b.byteOffset) {\n return false;\n }\n while (index-- > 0) {\n if (a[index] !== b[index]) {\n return false;\n }\n }\n return true;\n}\n/**\n * Whether the URL instances are equal in value.\n */\nfunction areUrlsEqual(a, b) {\n return (a.hostname === b.hostname\n && a.pathname === b.pathname\n && a.protocol === b.protocol\n && a.port === b.port\n && a.hash === b.hash\n && a.username === b.username\n && a.password === b.password);\n}\nfunction isPropertyEqual(a, b, state, property) {\n if ((property === REACT_OWNER || property === PREACT_OWNER || property === PREACT_VNODE)\n && (a.$$typeof || b.$$typeof)) {\n return true;\n }\n return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);\n}\n\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst toString = Object.prototype.toString;\n/**\n * Create a comparator method based on the type-specific equality comparators passed.\n */\nfunction createEqualityComparator(config) {\n const supportedComparatorMap = createSupportedComparatorMap(config);\n const { areArraysEqual, areDatesEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, areRegExpsEqual, areSetsEqual, getUnsupportedCustomComparator, } = config;\n /**\n * compare the value of the two objects and return true if they are equivalent in values\n */\n return function comparator(a, b, state) {\n // If the items are strictly equal, no need to do a value comparison.\n if (a === b) {\n return true;\n }\n // If either of the items are nullish and fail the strictly equal check\n // above, then they must be unequal.\n if (a == null || b == null) {\n return false;\n }\n const type = typeof a;\n if (type !== typeof b) {\n return false;\n }\n if (type !== 'object') {\n if (type === 'number' || type === 'bigint') {\n return areNumbersEqual(a, b, state);\n }\n if (type === 'function') {\n return areFunctionsEqual(a, b, state);\n }\n // If a primitive value that is not strictly equal, it must be unequal.\n return false;\n }\n const constructor = a.constructor;\n // Checks are listed in order of commonality of use-case:\n // 1. Common complex object types (plain object, array)\n // 2. Common data values (date, regexp)\n // 3. Less-common complex object types (map, set)\n // 4. Less-common data values (promise, primitive wrappers)\n // Inherently this is both subjective and assumptive, however\n // when reviewing comparable libraries in the wild this order\n // appears to be generally consistent.\n // Constructors should match, otherwise there is potential for false positives\n // between class and subclass or custom object and POJO.\n if (constructor !== b.constructor) {\n return false;\n }\n // Try to fast-path equality checks for other complex object types in the\n // same realm to avoid capturing the string tag. Strict equality is used\n // instead of `instanceof` because it is more performant for the common\n // use-case. If someone is creating a subclass from a native class, it will be\n // handled with the string tag comparison.\n if (constructor === Object) {\n return areObjectsEqual(a, b, state);\n }\n if (constructor === Array) {\n return areArraysEqual(a, b, state);\n }\n if (constructor === Date) {\n return areDatesEqual(a, b, state);\n }\n if (constructor === RegExp) {\n return areRegExpsEqual(a, b, state);\n }\n if (constructor === Map) {\n return areMapsEqual(a, b, state);\n }\n if (constructor === Set) {\n return areSetsEqual(a, b, state);\n }\n if (constructor === Promise) {\n // Avoid tag checks for promise values, since we know if they are not referentially equal\n // then they are not equal.\n return false;\n }\n // `isArray()` works on subclasses and is cross-realm, so we can avoid capturing\n // the string tag or doing an `instanceof` in edge cases.\n if (Array.isArray(a)) {\n return areArraysEqual(a, b, state);\n }\n // Since this is a custom object, capture the string tag to determining its type.\n // This is reasonably performant in modern environments like v8 and SpiderMonkey.\n const tag = toString.call(a);\n const supportedComparator = supportedComparatorMap[tag];\n if (supportedComparator) {\n return supportedComparator(a, b, state);\n }\n const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);\n if (unsupportedCustomComparator) {\n return unsupportedCustomComparator(a, b, state);\n }\n // If not matching any tags that require a specific type of comparison, then we hard-code false because\n // the only thing remaining is strict equality, which has already been compared. This is for a few reasons:\n // - Certain types that cannot be introspected (e.g., `WeakMap`). For these types, this is the only\n // comparison that can be made.\n // - For types that can be introspected but do not have an objective definition of what\n // equality is (`Error`, etc.), the subjective decision is to be conservative and strictly compare.\n // In all cases, these decisions should be reevaluated based on changes to the language and\n // common development practices.\n return false;\n };\n}\n/**\n * Create the configuration object used for building comparators.\n */\nfunction createEqualityComparatorConfig({ circular, createCustomConfig, strict, }) {\n let config = {\n areArrayBuffersEqual,\n areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,\n areDataViewsEqual,\n areDatesEqual: areDatesEqual,\n areErrorsEqual: areErrorsEqual,\n areFunctionsEqual: strictEqual,\n areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,\n areNumbersEqual: sameValueEqual,\n areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,\n arePrimitiveWrappersEqual: arePrimitiveWrappersEqual,\n areRegExpsEqual: areRegExpsEqual,\n areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,\n areTypedArraysEqual: strict\n ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict)\n : areTypedArraysEqual,\n areUrlsEqual: areUrlsEqual,\n getUnsupportedCustomComparator: undefined,\n };\n if (createCustomConfig) {\n config = Object.assign({}, config, createCustomConfig(config));\n }\n if (circular) {\n const areArraysEqual = createIsCircular(config.areArraysEqual);\n const areMapsEqual = createIsCircular(config.areMapsEqual);\n const areObjectsEqual = createIsCircular(config.areObjectsEqual);\n const areSetsEqual = createIsCircular(config.areSetsEqual);\n config = Object.assign({}, config, {\n areArraysEqual,\n areMapsEqual,\n areObjectsEqual,\n areSetsEqual,\n });\n }\n return config;\n}\n/**\n * Default equality comparator pass-through, used as the standard `isEqual` creator for\n * use inside the built comparator.\n */\nfunction createInternalEqualityComparator(compare) {\n return function (a, b, _indexOrKeyA, _indexOrKeyB, _parentA, _parentB, state) {\n return compare(a, b, state);\n };\n}\n/**\n * Create the `isEqual` function used by the consuming application.\n */\nfunction createIsEqual({ circular, comparator, createState, equals, strict }) {\n if (createState) {\n return function isEqual(a, b) {\n const { cache = circular ? new WeakMap() : undefined, meta } = createState();\n return comparator(a, b, {\n cache,\n equals,\n meta,\n strict,\n });\n };\n }\n if (circular) {\n return function isEqual(a, b) {\n return comparator(a, b, {\n cache: new WeakMap(),\n equals,\n meta: undefined,\n strict,\n });\n };\n }\n const state = {\n cache: undefined,\n equals,\n meta: undefined,\n strict,\n };\n return function isEqual(a, b) {\n return comparator(a, b, state);\n };\n}\n/**\n * Create a map of `toString()` values to their respective handlers for `tag`-based lookups.\n */\nfunction createSupportedComparatorMap({ areArrayBuffersEqual, areArraysEqual, areDataViewsEqual, areDatesEqual, areErrorsEqual, areFunctionsEqual, areMapsEqual, areNumbersEqual, areObjectsEqual, arePrimitiveWrappersEqual, areRegExpsEqual, areSetsEqual, areTypedArraysEqual, areUrlsEqual, }) {\n return {\n '[object Arguments]': areObjectsEqual,\n '[object Array]': areArraysEqual,\n '[object ArrayBuffer]': areArrayBuffersEqual,\n '[object AsyncGeneratorFunction]': areFunctionsEqual,\n '[object BigInt]': areNumbersEqual,\n '[object BigInt64Array]': areTypedArraysEqual,\n '[object BigUint64Array]': areTypedArraysEqual,\n '[object Boolean]': arePrimitiveWrappersEqual,\n '[object DataView]': areDataViewsEqual,\n '[object Date]': areDatesEqual,\n // If an error tag, it should be tested explicitly. Like RegExp, the properties are not\n // enumerable, and therefore will give false positives if tested like a standard object.\n '[object Error]': areErrorsEqual,\n '[object Float16Array]': areTypedArraysEqual,\n '[object Float32Array]': areTypedArraysEqual,\n '[object Float64Array]': areTypedArraysEqual,\n '[object Function]': areFunctionsEqual,\n '[object GeneratorFunction]': areFunctionsEqual,\n '[object Int8Array]': areTypedArraysEqual,\n '[object Int16Array]': areTypedArraysEqual,\n '[object Int32Array]': areTypedArraysEqual,\n '[object Map]': areMapsEqual,\n '[object Number]': arePrimitiveWrappersEqual,\n '[object Object]': (a, b, state) => \n // The exception for value comparison is custom `Promise`-like class instances. These should\n // be treated the same as standard `Promise` objects, which means strict equality, and if\n // it reaches this point then that strict equality comparison has already failed.\n typeof a.then !== 'function' && typeof b.then !== 'function' && areObjectsEqual(a, b, state),\n // For RegExp, the properties are not enumerable, and therefore will give false positives if\n // tested like a standard object.\n '[object RegExp]': areRegExpsEqual,\n '[object Set]': areSetsEqual,\n '[object String]': arePrimitiveWrappersEqual,\n '[object URL]': areUrlsEqual,\n '[object Uint8Array]': areTypedArraysEqual,\n '[object Uint8ClampedArray]': areTypedArraysEqual,\n '[object Uint16Array]': areTypedArraysEqual,\n '[object Uint32Array]': areTypedArraysEqual,\n };\n}\n\n/**\n * Whether the items passed are deeply-equal in value.\n */\nconst deepEqual = createCustomEqual();\n/**\n * Whether the items passed are deeply-equal in value based on strict comparison.\n */\nconst strictDeepEqual = createCustomEqual({ strict: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references.\n */\nconst circularDeepEqual = createCustomEqual({ circular: true });\n/**\n * Whether the items passed are deeply-equal in value, including circular references,\n * based on strict comparison.\n */\nconst strictCircularDeepEqual = createCustomEqual({\n circular: true,\n strict: true,\n});\n/**\n * Whether the items passed are shallowly-equal in value.\n */\nconst shallowEqual = createCustomEqual({\n createInternalComparator: () => sameValueEqual,\n});\n/**\n * Whether the items passed are shallowly-equal in value based on strict comparison\n */\nconst strictShallowEqual = createCustomEqual({\n strict: true,\n createInternalComparator: () => sameValueEqual,\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references.\n */\nconst circularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: () => sameValueEqual,\n});\n/**\n * Whether the items passed are shallowly-equal in value, including circular references,\n * based on strict comparison.\n */\nconst strictCircularShallowEqual = createCustomEqual({\n circular: true,\n createInternalComparator: () => sameValueEqual,\n strict: true,\n});\n/**\n * Create a custom equality comparison method.\n *\n * This can be done to create very targeted comparisons in extreme hot-path scenarios\n * where the standard methods are not performant enough, but can also be used to provide\n * support for legacy environments that do not support expected features like\n * `RegExp.prototype.flags` out of the box.\n */\nfunction createCustomEqual(options = {}) {\n const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false, } = options;\n const config = createEqualityComparatorConfig(options);\n const comparator = createEqualityComparator(config);\n const equals = createCustomInternalComparator\n ? createCustomInternalComparator(comparator)\n : createInternalEqualityComparator(comparator);\n return createIsEqual({ circular, comparator, createState, equals, strict });\n}\n\nexport { circularDeepEqual, circularShallowEqual, createCustomEqual, deepEqual, sameValueEqual, sameValueZeroEqual, shallowEqual, strictCircularDeepEqual, strictCircularShallowEqual, strictDeepEqual, strictEqual, strictShallowEqual };\n","import {\n ArrayProperty,\n CollectionWithRelations,\n CollectionWithSubcollections,\n EntityCollection,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty,\n getDataSourceCapabilities\n} from \"@rebasepro/types\";\nimport { deepEqual } from \"fast-equals\";\n\nimport { enumToObjectEntries, getSubcollections, getTableName, resolveCollectionRelations, findRelation, sanitizeRelation } from \"../util\";\nimport { removeFunctions, mergeDeep, deepClone } from \"@rebasepro/utils\";\n\nexport class CollectionRegistry {\n\n // Normalized runtime layer (used by Data Grid / UI)\n private collectionsByTableName = new Map<string, EntityCollection>();\n private collectionsBySlug = new Map<string, EntityCollection>();\n private rootCollections: EntityCollection[] = [];\n private cachedCollectionsList: EntityCollection[] | null = null;\n\n // Raw configuration layer (used by Collection Editor AST generator)\n private rawCollectionsByTableName = new Map<string, EntityCollection>();\n private rawCollectionsBySlug = new Map<string, EntityCollection>();\n private rawRootCollections: EntityCollection[] = [];\n private cachedRawCollectionsList: EntityCollection[] | null = null;\n\n // Snapshot of raw input for idempotency check — compared BEFORE normalization\n // to avoid the issue where normalization creates new objects that always fail equality.\n private lastRawInputSnapshot: ReturnType<typeof removeFunctions>[] | null = null;\n\n constructor(collections?: EntityCollection[]) {\n if (collections) {\n this.registerMultiple(collections);\n }\n }\n\n reset() {\n this.collectionsByTableName.clear();\n this.collectionsBySlug.clear();\n this.rootCollections = [];\n this.cachedCollectionsList = null;\n\n this.rawCollectionsByTableName.clear();\n this.rawCollectionsBySlug.clear();\n this.rawRootCollections = [];\n this.cachedRawCollectionsList = null;\n }\n\n /**\n * Registers a collection and its subcollections recursively.\n * Returns true if the collections have changed, false otherwise.\n *\n * Idempotent: compares the raw input (before normalization) against a stored\n * snapshot. Only re-normalizes and re-registers when the raw input actually changed.\n * @param collections\n */\n registerMultiple(collections: EntityCollection[]): boolean {\n // Compare raw input BEFORE normalization to detect actual changes.\n // This avoids the old issue where normalization creates new objects\n // that always fail deep-equal even when the source data is identical.\n const rawSnapshot = collections.map(c => removeFunctions(c));\n if (this.lastRawInputSnapshot && deepEqual(this.lastRawInputSnapshot, rawSnapshot)) {\n return false;\n }\n\n this.reset();\n // Phase 0: Populate maps with raw collections first for string target resolution\n collections.forEach((c) => {\n if (c.slug) {\n this.collectionsBySlug.set(c.slug, c);\n }\n this.collectionsByTableName.set(getTableName(c), c);\n });\n\n const normalizedCollections = collections.map(c => this.normalizeCollection({ ...c }));\n\n // Phase 1: Register all top-level collections first (without recursion).\n // This ensures that injected entityViews (e.g. History tab) are preserved.\n // Without this, _registerRecursively could register a relation-target collection\n // (e.g. Tags from Posts.relations) using the raw module object (without injected views)\n // before the top-level Tags collection (with injected views) gets its turn.\n normalizedCollections.forEach((c, index) => {\n const raw = deepClone(collections[index]);\n this.rootCollections.push(c);\n this.rawRootCollections.push(raw);\n\n const normalized = this.normalizeCollection(c);\n this.collectionsByTableName.set(getTableName(normalized), normalized);\n this.rawCollectionsByTableName.set(getTableName(raw), raw);\n if (normalized.slug) {\n this.collectionsBySlug.set(normalized.slug, normalized);\n }\n if (raw.slug) {\n this.rawCollectionsBySlug.set(raw.slug, raw);\n }\n });\n\n // Phase 2: Now recurse into subcollections (relations, etc.)\n normalizedCollections.forEach((c) => {\n const subcollections = getSubcollections(c);\n if (subcollections && subcollections.length > 0) {\n subcollections.forEach((subCollection) => {\n if (!subCollection) return;\n // Spread to avoid mutating the original target() return value\n this._registerRecursively(this.normalizeCollection({ ...subCollection }), deepClone(subCollection));\n });\n }\n });\n\n // Store the snapshot for future comparisons\n this.lastRawInputSnapshot = rawSnapshot;\n\n return true;\n }\n\n register(collection: EntityCollection, rawCollection?: EntityCollection) {\n const raw = rawCollection ? deepClone(rawCollection) : deepClone(collection);\n\n this.rootCollections.push(collection);\n this.rawRootCollections.push(raw);\n\n this._registerRecursively(collection, raw);\n }\n\n private _registerRecursively(collection: EntityCollection, rawCollection: EntityCollection) {\n if (this.collectionsByTableName.has(getTableName(collection))) {\n return;\n }\n\n const normalizedCollection = this.normalizeCollection(collection);\n this.collectionsByTableName.set(getTableName(normalizedCollection), normalizedCollection);\n this.rawCollectionsByTableName.set(getTableName(rawCollection), rawCollection);\n\n if (normalizedCollection.slug) {\n this.collectionsBySlug.set(normalizedCollection.slug, normalizedCollection);\n }\n if (rawCollection.slug) {\n this.rawCollectionsBySlug.set(rawCollection.slug, rawCollection);\n }\n\n // Use the normalized collection for subcollection discovery so that\n // both inline-extracted and explicit relations are considered.\n const subcollections = getSubcollections(normalizedCollection);\n\n if (subcollections && subcollections.length > 0) {\n subcollections.forEach((subCollection) => {\n if (!subCollection) return;\n // Spread to avoid mutating the original target() return value\n this._registerRecursively(this.normalizeCollection({ ...subCollection }), deepClone(subCollection));\n });\n }\n }\n\n public normalizeCollection(collection: EntityCollection): EntityCollection {\n // Work on a shallow copy to avoid mutating the caller's reference.\n // This is critical for idempotency (the raw input must not be changed)\n // and for preventing mutation of module-level collection singletons.\n const result = { ...collection } as EntityCollection;\n\n // 1. Extract relations from properties that have inline config (target set)\n const extractedRelations = this.extractRelationsFromProperties(result.properties);\n\n // 2. Merge with manual relations[] (manual entries win on name conflict)\n const relResult = result as CollectionWithRelations;\n const manualRelations = getDataSourceCapabilities(result.driver).supportsRelations ? (relResult.relations ?? []) : [];\n const mergedRelationsRaw = [...extractedRelations];\n for (const manual of manualRelations) {\n const name = manual.relationName;\n if (!name) {\n mergedRelationsRaw.push(manual);\n } else {\n const existingIndex = mergedRelationsRaw.findIndex(r => r.relationName === name);\n if (existingIndex === -1) {\n mergedRelationsRaw.push(manual);\n } else {\n // Merge manual into existing, preserving custom fields like 'collection'\n mergedRelationsRaw[existingIndex] = {\n ...manual,\n ...mergedRelationsRaw[existingIndex]\n };\n }\n }\n }\n\n let mergedRelations = mergedRelationsRaw;\n\n // 2b. Sanitize each relation so derived fields (through, localKey,\n // foreignKeyOnTarget, etc.) are populated. Without this the\n // property.relation stamp is missing junction-table metadata and\n // the backend cannot fetch many-to-many data.\n if (getDataSourceCapabilities(result.driver).supportsRelations) {\n mergedRelations = mergedRelationsRaw.map(r => {\n try {\n return sanitizeRelation(r, result, (slug) => this.get(slug));\n } catch {\n // sanitizeRelation may throw for incomplete configs\n // (e.g. missing target). Keep the raw relation as-is.\n return r;\n }\n });\n\n // 3. Set the merged relations on the result copy\n relResult.relations = mergedRelations;\n }\n\n // 4. Normalize properties (which stamps relation on each property)\n const properties: Properties = this.normalizeProperties(result.properties, mergedRelations);\n result.properties = properties;\n\n // Populate childCollections from driver-specific fields\n if (!result.childCollections) {\n if (getDataSourceCapabilities(result.driver).supportsSubcollections && (result as CollectionWithSubcollections).subcollections) {\n result.childCollections = (result as CollectionWithSubcollections).subcollections;\n } else if (getDataSourceCapabilities(result.driver).supportsRelations && relResult.relations) {\n const manyRelations = relResult.relations.filter((r: Relation) => r.cardinality === \"many\");\n if (manyRelations.length > 0) {\n result.childCollections = () => manyRelations.map((r: Relation) => {\n const target = r.target();\n return r.overrides ? mergeDeep(target, r.overrides) : target;\n });\n }\n }\n }\n\n return result;\n }\n\n /**\n * Extract Relation[] from properties that have inline relation config (i.e. `target` is set).\n * This allows developers to define relations directly on properties without a separate\n * `relations[]` entry on the collection.\n */\n private extractRelationsFromProperties(properties: Properties): Relation[] {\n const relations: Relation[] = [];\n for (const [key, property] of Object.entries(properties as Record<string, Property>)) {\n if (property.type === \"relation\") {\n const relProp = property as RelationProperty;\n // Support both inline config (target directly on property)\n // and nested config (target inside property.relation)\n const target = relProp.target ?? relProp.relation?.target;\n if (target) {\n const relationName = relProp.relationName ?? relProp.relation?.relationName ?? key;\n relations.push({\n relationName,\n target,\n cardinality: relProp.cardinality ?? relProp.relation?.cardinality ?? \"one\",\n direction: relProp.direction ?? relProp.relation?.direction ?? \"owning\",\n inverseRelationName: relProp.inverseRelationName ?? relProp.relation?.inverseRelationName,\n localKey: relProp.localKey ?? relProp.relation?.localKey,\n foreignKeyOnTarget: relProp.foreignKeyOnTarget ?? relProp.relation?.foreignKeyOnTarget,\n through: relProp.through ?? relProp.relation?.through,\n joinPath: relProp.joinPath ?? relProp.relation?.joinPath,\n onUpdate: relProp.onUpdate ?? relProp.relation?.onUpdate,\n onDelete: relProp.onDelete ?? relProp.relation?.onDelete,\n overrides: relProp.overrides ?? relProp.relation?.overrides\n });\n }\n } else if (property.type === \"map\" && property.properties) {\n // Recurse into map children to extract nested inline relations\n relations.push(...this.extractRelationsFromProperties(property.properties));\n }\n }\n return relations;\n }\n\n private normalizeProperties(properties: Properties, relations: Relation[]): Properties {\n const newProperties: Properties = {};\n for (const key in properties) {\n newProperties[key] = this.normalizeProperty(key, properties[key], relations);\n }\n return newProperties;\n }\n\n private normalizeProperty(key: string, property: Property, relations: Relation[]): Property {\n const newProperty = { ...property };\n\n if (newProperty.type === \"map\" && newProperty.properties) {\n newProperty.properties = this.normalizeProperties(newProperty.properties, relations);\n } else if (newProperty.type === \"array\") {\n // Cast to get a properly typed mutable reference\n const arrayProp = newProperty as ArrayProperty;\n if (arrayProp.of) {\n if (Array.isArray(arrayProp.of)) {\n (arrayProp as { of: Property | Property[] }).of = arrayProp.of.map((p, i) => this.normalizeProperty(`${key}[${i}]`, p, relations));\n } else {\n arrayProp.of = this.normalizeProperty(`${key}.of`, arrayProp.of, relations);\n }\n } else if (arrayProp.oneOf && arrayProp.oneOf.properties) {\n arrayProp.oneOf.properties = this.normalizeProperties(arrayProp.oneOf.properties, relations);\n }\n } else if ((newProperty.type === \"string\" || newProperty.type === \"number\") && newProperty.enum) {\n const stringOrNumberProperty = newProperty as StringProperty | NumberProperty;\n if (typeof stringOrNumberProperty.enum === \"object\" && !Array.isArray(stringOrNumberProperty.enum)) {\n stringOrNumberProperty.enum = enumToObjectEntries(stringOrNumberProperty.enum)?.filter((value) => value && (value.id || value.id === 0) && value.label) ?? [];\n }\n } else if (newProperty.type === \"relation\") {\n const relationProperty = newProperty as RelationProperty;\n const name = relationProperty.relationName || key;\n const relation = relations.find(r => r.relationName === name);\n if (relation) {\n // we attach the resolved relation to the property\n relationProperty.relation = relation;\n } else {\n console.warn(`Could not find relation for property '${key}' with relationName: ${name}`);\n }\n }\n\n return newProperty;\n }\n\n get(path: string): EntityCollection | undefined {\n // First try slug lookup\n const bySlug = this.collectionsBySlug.get(path);\n if (bySlug) return bySlug;\n\n // Fallback: normalize hyphens → underscores (URLs use kebab-case, slugs use snake_case)\n if (path.includes(\"-\")) {\n const normalized = path.replace(/-/g, \"_\");\n const byNormalized = this.collectionsBySlug.get(normalized);\n if (byNormalized) return byNormalized;\n }\n\n // Fallback to table name lookup\n return this.collectionsByTableName.get(path);\n }\n\n /**\n * Gets the pristine, un-normalized collection exactly as it was provided.\n * Useful for the AST editor so it doesn't accidentally serialize injected metadata back to disk.\n */\n getRaw(path: string): EntityCollection | undefined {\n const bySlug = this.rawCollectionsBySlug.get(path);\n if (bySlug) return bySlug;\n\n // Fallback: normalize hyphens → underscores (URLs use kebab-case, slugs use snake_case)\n if (path.includes(\"-\")) {\n const normalized = path.replace(/-/g, \"_\");\n const byNormalized = this.rawCollectionsBySlug.get(normalized);\n if (byNormalized) return byNormalized;\n }\n\n return this.rawCollectionsByTableName.get(path);\n }\n\n /**\n * Get collection by resolving multi-segment paths through relations\n * e.g., \"authors/70/posts\" resolves to the posts collection\n */\n getCollectionByPath(collectionPath: string): EntityCollection | undefined {\n // Handle simple single collection path\n if (!collectionPath.includes(\"/\")) {\n return this.get(collectionPath);\n }\n\n // Handle multi-segment paths by resolving through relations\n const pathSegments = collectionPath.split(\"/\").filter(p => p);\n\n if (pathSegments.length < 3 || pathSegments.length % 2 === 0) {\n throw new Error(`Invalid relation path: ${collectionPath}. Expected format: collection/id/relation or collection/id/relation/id/relation`);\n }\n\n // Start with the root collection\n const rootCollectionPath = pathSegments[0];\n let currentCollection = this.get(rootCollectionPath);\n\n if (!currentCollection) {\n throw new Error(`Root collection not found: ${rootCollectionPath}`);\n }\n\n // Navigate through the path using relations\n for (let i = 2; i < pathSegments.length; i += 2) {\n const relationKey = pathSegments[i];\n\n // Get relations for current collection\n if (!getDataSourceCapabilities(currentCollection.driver).supportsRelations) {\n throw new Error(`Relation path navigation requires a collection that supports relations, but '${currentCollection.slug}' uses driver '${currentCollection.driver}'`);\n }\n const resolvedRelations = resolveCollectionRelations(currentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n\n if (!relation) {\n throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);\n }\n\n // Move to the target collection\n const target = relation.target();\n const targetRelationKey = relation.relationName || target.slug;\n const targetSlug = relation.overrides?.slug ?? targetRelationKey;\n currentCollection = this.get(targetSlug) || this.normalizeCollection(target);\n\n // If there are more segments, continue navigation\n if (i + 1 < pathSegments.length) {\n // Skip entity ID segment\n }\n }\n\n return currentCollection;\n }\n\n getCollections(): EntityCollection[] {\n if (!this.cachedCollectionsList) {\n this.cachedCollectionsList = Array.from(this.collectionsByTableName.values());\n }\n return this.cachedCollectionsList;\n }\n\n getRawCollections(): EntityCollection[] {\n if (!this.cachedRawCollectionsList) {\n this.cachedRawCollectionsList = Array.from(this.rawCollectionsByTableName.values());\n }\n return this.cachedRawCollectionsList;\n }\n\n /**\n * Resolves a multi-segment path like \"products/123/locales\" and returns\n * information about the collections and entity IDs along the path\n */\n resolvePathToCollections(path: string): {\n collections: EntityCollection[],\n entityIds: (string | number)[],\n finalCollection: EntityCollection\n } {\n const pathSegments = path.split(\"/\").filter(p => p);\n\n if (pathSegments.length === 0) {\n throw new Error(`Invalid path: ${path}`);\n }\n\n if (pathSegments.length % 2 !== 1) {\n throw new Error(`Invalid collection path: ${path}. It must have an odd number of segments.`);\n }\n\n const collections: EntityCollection[] = [];\n const entityIds: (string | number)[] = [];\n\n // Start with the first collection\n let currentCollection = this.get(pathSegments[0]);\n\n if (!currentCollection) {\n throw new Error(`Unknown collection path or slug: ${pathSegments[0]}`);\n }\n\n collections.push(currentCollection);\n\n // Process the rest of the path in pairs (entityId, subcollectionSlug)\n for (let i = 1; i < pathSegments.length; i += 2) {\n const entityId = pathSegments[i];\n entityIds.push(entityId);\n\n if (i + 1 < pathSegments.length) {\n const subcollectionSlug = pathSegments[i + 1];\n const subcollections: EntityCollection[] | undefined = getSubcollections(currentCollection);\n if (!subcollections || subcollections.length === 0) {\n throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);\n }\n\n const subcollection: EntityCollection | undefined = subcollections.find(c => c.slug === subcollectionSlug);\n if (!subcollection) {\n throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);\n }\n currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);\n collections.push(currentCollection);\n }\n }\n\n return {\n collections,\n entityIds,\n finalCollection: currentCollection\n };\n }\n\n}\n\n","import { FindParams, Entity, FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator, LogicalCondition, WhereValue, FilterCondition } from \"@rebasepro/types\";\n\nexport function or(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition {\n return { type: \"or\",\nconditions };\n}\n\nexport function and(...conditions: (FilterCondition | LogicalCondition)[]): LogicalCondition {\n return { type: \"and\",\nconditions };\n}\n\nexport function cond(column: string, operator: FilterOperator, value: unknown): FilterCondition {\n return { column,\noperator,\nvalue };\n}\n\nexport class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {\n private params: FindParams = { where: {} };\n\n constructor(private collection: CollectionAccessor<M>) {}\n\n /**\n * Add a filter condition to your query.\n * @example\n * client.collection('users').where('age', '>=', 18).find()\n */\n where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: FilterOperator, value?: unknown): this {\n // Handle LogicalCondition signature\n if (typeof columnOrCondition === \"object\" && columnOrCondition !== null && \"type\" in columnOrCondition) {\n this.params.logical = columnOrCondition as LogicalCondition;\n return this;\n }\n\n if (!this.params.where) {\n this.params.where = {};\n }\n\n const column = columnOrCondition as string;\n const condition: [FilterOperator, unknown] = [operator!, value];\n const existing = this.params.where[column];\n\n if (existing === undefined) {\n this.params.where[column] = condition;\n } else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) {\n (this.params.where[column] as [FilterOperator, unknown][]).push(condition);\n } else {\n // Convert existing single tuple/value into array of tuples\n let firstCondition: [FilterOperator, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [FilterOperator, unknown];\n } else {\n firstCondition = [\"==\", existing];\n }\n this.params.where[column] = [firstCondition, condition];\n }\n\n return this;\n }\n\n /**\n * Order the results by a specific column.\n * @example\n * client.collection('users').orderBy('createdAt', 'desc').find()\n */\n orderBy(column: keyof M & string, ascending: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = `${column}:${ascending}`;\n return this;\n }\n\n /**\n * Limit the number of results returned.\n */\n limit(count: number): this {\n this.params.limit = count;\n return this;\n }\n\n /**\n * Skip the first N results.\n */\n offset(count: number): this {\n this.params.offset = count;\n return this;\n }\n\n /**\n * Set a free-text search string if supported by the backend.\n */\n search(searchString: string): this {\n this.params.searchString = searchString;\n return this;\n }\n\n /**\n * Include related entities in the response.\n * Relations will be populated with full entity data instead of just IDs.\n *\n * @param relations - Relation names to include, or \"*\" for all.\n * @example\n * // Include specific relations\n * client.data.posts.include(\"tags\", \"author\").find()\n *\n * // Include all relations\n * client.data.posts.include(\"*\").find()\n */\n include(...relations: string[]): this {\n this.params.include = relations;\n return this;\n }\n\n /**\n * Execute the find query and return the results.\n */\n async find(): Promise<FindResponse<M>> {\n return this.collection.find(this.params) as Promise<FindResponse<M>>;\n }\n\n /**\n * Listen to realtime updates matching this query.\n */\n listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void {\n if (!this.collection.listen) {\n throw new Error(\"Listen is only available when RebaseClient is configured with a websocketUrl.\");\n }\n return this.collection.listen(this.params, onUpdate, onError);\n }\n}\n","import {\n DataDriver,\n RebaseData,\n CollectionAccessor,\n FindParams,\n FindResponse,\n Entity,\n EntityValues,\n FilterValues,\n WhereFilterOp,\n WhereFieldValue,\n WhereFilterOpShort,\n LogicalCondition,\n WhereValue\n} from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { QueryBuilder } from \"./query_builder\";\n\n/**\n * Convert where-clause filter object to the internal DataDriver FilterValues format.\n *\n * Supports multiple value formats:\n * - PostgREST string: { status: \"eq.published\", age: \"gte.18\" }\n * - Equality shorthand: { company_profile_id: null, status: \"active\", age: 18 }\n * - Tuple syntax: { age: [\">=\", 18], role: [\"in\", [\"admin\", \"editor\"]] }\n *\n * Internal: { status: [\"==\", \"published\"], age: [\">=\", 18] }\n */\nfunction convertWhereToFilter(where?: Record<string, WhereFieldValue>): FilterValues<string> | undefined {\n if (!where) return undefined;\n\n const operatorMap: Record<string, WhereFilterOp> = {\n \"eq\": \"==\",\n \"neq\": \"!=\",\n \"gt\": \">\",\n \"gte\": \">=\",\n \"lt\": \"<\",\n \"lte\": \"<=\",\n \"in\": \"in\",\n \"nin\": \"not-in\",\n \"not-in\": \"not-in\",\n \"cs\": \"array-contains\",\n \"csa\": \"array-contains-any\",\n \"==\": \"==\",\n\"!=\": \"!=\",\n \">\": \">\",\n\">=\": \">=\",\n \"<\": \"<\",\n\"<=\": \"<=\",\n \"array-contains\": \"array-contains\",\n \"array-contains-any\": \"array-contains-any\"\n };\n\n const filter: FilterValues<string> = {};\n\n for (const [field, rawValue] of Object.entries(where)) {\n // Handle null → equality\n if (rawValue === null) {\n filter[field] = [\"==\", null];\n continue;\n }\n\n // Handle boolean → equality\n if (typeof rawValue === \"boolean\") {\n filter[field] = [\"==\", rawValue];\n continue;\n }\n\n // Handle number → equality\n if (typeof rawValue === \"number\") {\n filter[field] = [\"==\", rawValue];\n continue;\n }\n\n // Handle tuple or array of tuples\n if (Array.isArray(rawValue)) {\n const conditions: [WhereFilterOpShort, unknown][] = Array.isArray(rawValue[0])\n ? (rawValue as [WhereFilterOpShort, unknown][])\n : [rawValue as [WhereFilterOpShort, unknown]];\n\n const mappedConditions: [WhereFilterOp, unknown][] = conditions.map(([rawOp, val]) => {\n const mappedOp = operatorMap[rawOp] ?? \"==\";\n return [mappedOp, val];\n });\n\n filter[field] = Array.isArray(rawValue[0]) ? mappedConditions : mappedConditions[0];\n continue;\n }\n\n // Handle PostgREST string format: \"op.value\"\n if (typeof rawValue === \"string\") {\n const dotIndex = rawValue.indexOf(\".\");\n if (dotIndex === -1) {\n // Plain string equality\n filter[field] = [\"==\", rawValue];\n continue;\n }\n\n const op = rawValue.substring(0, dotIndex);\n let value: unknown = rawValue.substring(dotIndex + 1);\n\n // Parse list values like \"(admin,editor)\"\n if (typeof value === \"string\" && value.startsWith(\"(\") && value.endsWith(\")\")) {\n value = value.slice(1, -1).split(\",\").map((v: string) => v.trim());\n }\n\n // Parse null string\n if (value === \"null\") {\n value = null;\n }\n // Parse boolean strings\n else if (value === \"true\") {\n value = true;\n } else if (value === \"false\") {\n value = false;\n }\n // Try to parse numbers\n else if (typeof value === \"string\" && !isNaN(Number(value)) && value.trim() !== \"\") {\n value = Number(value);\n }\n\n const mappedOp = operatorMap[op];\n if (mappedOp) {\n filter[field] = [mappedOp, value];\n }\n }\n }\n\n return Object.keys(filter).length > 0 ? filter : undefined;\n}\n\n/**\n * Parse an orderBy string like \"created_at:desc\" into [field, direction].\n */\nfunction parseOrderBy(orderBy?: string): [string, \"asc\" | \"desc\"] | undefined {\n if (!orderBy) return undefined;\n const parts = orderBy.split(\":\");\n const field = parts[0];\n const direction = (parts[1] as \"asc\" | \"desc\") || \"asc\";\n return [field, direction];\n}\n\nfunction createDriverAccessor<M extends Record<string, unknown> = Record<string, unknown>>(\n driver: DataDriver,\n slug: string\n): CollectionAccessor<M> {\n const accessor: CollectionAccessor<M> = {\n async find(params?: FindParams): Promise<FindResponse<M>> {\n const orderParsed = parseOrderBy(params?.orderBy);\n const entities = await driver.fetchCollection<M>({\n path: slug,\n limit: params?.limit,\n offset: params?.offset,\n filter: convertWhereToFilter(params?.where),\n orderBy: orderParsed?.[0],\n order: orderParsed?.[1],\n searchString: params?.searchString\n });\n const limit = params?.limit ?? 20;\n const offset = params?.offset ?? 0;\n return {\n data: entities,\n meta: {\n total: entities.length,\n limit,\n offset,\n hasMore: entities.length >= limit\n }\n };\n },\n\n async findById(id: string | number): Promise<Entity<M> | undefined> {\n return driver.fetchEntity<M>({ path: slug,\nentityId: id });\n },\n\n async create(data: Partial<EntityValues<M>>, id?: string | number): Promise<Entity<M>> {\n return driver.saveEntity<M>({\n path: slug,\n values: data,\n entityId: id,\n status: \"new\"\n });\n },\n\n async update(id: string | number, data: Partial<EntityValues<M>>): Promise<Entity<M>> {\n return driver.saveEntity<M>({\n path: slug,\n values: data,\n entityId: id,\n status: \"existing\"\n });\n },\n\n async delete(id: string | number): Promise<void> {\n return driver.deleteEntity({\n entity: { id,\npath: slug,\nvalues: {} as Record<string, unknown> }\n });\n },\n\n deleteAll: driver.deleteAll\n ? async (): Promise<void> => {\n return driver.deleteAll!(slug);\n }\n : undefined,\n\n count: driver.countEntities\n ? async (params?: FindParams): Promise<number> => {\n return driver.countEntities!({\n path: slug,\n filter: convertWhereToFilter(params?.where)\n });\n }\n : undefined,\n\n listen: driver.listenCollection\n ? (params: FindParams | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void) => {\n const orderParsed = parseOrderBy(params?.orderBy);\n const limit = params?.limit ?? 20;\n const offset = params?.offset ?? 0;\n return driver.listenCollection!<M>({\n path: slug,\n limit: params?.limit,\n offset: params?.offset,\n filter: convertWhereToFilter(params?.where),\n orderBy: orderParsed?.[0],\n order: orderParsed?.[1],\n searchString: params?.searchString,\n onUpdate: (entities) => {\n onUpdate({\n data: entities,\n meta: {\n total: entities.length,\n limit,\n offset,\n hasMore: entities.length >= limit\n }\n });\n },\n onError\n });\n } : undefined,\n\n listenById: driver.listenEntity\n ? (id: string | number, onUpdate: (entity: Entity<M> | undefined) => void, onError?: (error: Error) => void) => {\n return driver.listenEntity!<M>({\n path: slug,\n entityId: id,\n onUpdate: (entity) => onUpdate(entity ?? undefined),\n onError\n });\n } : undefined,\n\n // Fluent Query Builder\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOpShort, value?: unknown) {\n const builder = new QueryBuilder<M>(accessor);\n if (typeof columnOrCondition === \"object\") {\n return builder.where(columnOrCondition);\n }\n return builder.where(columnOrCondition as keyof M & string, operator!, value as WhereValue<M[keyof M & string]>);\n },\n orderBy(column: keyof M & string, ascending?: \"asc\" | \"desc\") {\n return new QueryBuilder<M>(accessor).orderBy(column, ascending);\n },\n limit(count: number) {\n return new QueryBuilder<M>(accessor).limit(count);\n },\n offset(count: number) {\n return new QueryBuilder<M>(accessor).offset(count);\n },\n search(searchString: string) {\n return new QueryBuilder<M>(accessor).search(searchString);\n },\n include(...relations: string[]) {\n return new QueryBuilder<M>(accessor).include(...relations);\n }\n };\n\n return accessor;\n}\n\n/**\n * Build a `RebaseData` object from a `DataDriver` using JavaScript Proxy.\n *\n * This is the key bridge: any property access like `data.products` returns\n * a `CollectionAccessor` backed by the underlying DataDriver, without\n * needing per-collection code generation.\n *\n * @example\n * const data = buildRebaseData(driver);\n * await data.products.create({ name: \"Camera\", price: 299 });\n * const { data: items } = await data.products.find({ where: { status: \"eq.published\" } });\n */\nexport function buildRebaseData(driver: DataDriver): RebaseData {\n const cache = new Map<string, CollectionAccessor>();\n\n function getAccessor(slug: string): CollectionAccessor {\n let accessor = cache.get(slug);\n if (!accessor) {\n accessor = createDriverAccessor(driver, slug);\n cache.set(slug, accessor);\n }\n return accessor;\n }\n\n const target = {\n collection: getAccessor\n } as RebaseData;\n\n return new Proxy(target, {\n get(_target, prop: string | symbol) {\n if (prop === \"collection\") return getAccessor;\n // Ignore Symbol properties (e.g. Symbol.toPrimitive, Symbol.iterator)\n if (typeof prop === \"symbol\") return undefined;\n // Ignore internal JS properties\n if (prop === \"then\" || prop === \"toJSON\" || prop === \"$$typeof\") return undefined;\n\n // Convert camelCase property names to snake_case slugs\n const slug = toSnakeCase(prop);\n return getAccessor(slug);\n }\n });\n}\n","import { PgTable, AnyPgColumn } from \"drizzle-orm/pg-core\";\nimport { EntityCollection, Property } from \"@rebasepro/types\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { getTableName } from \"@rebasepro/common\";\n\n/**\n * Shared helper functions for entity operations.\n * These are used by EntityFetchService, EntityPersistService, and RelationService.\n *\n * All functions that need collection/table lookups require an explicit\n * `PostgresCollectionRegistry` instance — there is no global singleton.\n */\n\n/**\n * Interface for Drizzle column metadata introspection.\n * Replaces unsafe `as Record<string, unknown>` double-cast chains.\n */\nexport interface DrizzleColumnMeta {\n columnType?: string;\n dataType?: string;\n primary?: boolean;\n}\n\n/** Safely extract Drizzle column metadata from a column object. */\nexport function getColumnMeta(col: AnyPgColumn): DrizzleColumnMeta {\n const raw = col as unknown as Record<string | symbol, unknown>;\n return {\n columnType: typeof raw.columnType === \"string\" ? raw.columnType : undefined,\n dataType: typeof raw.dataType === \"string\" ? raw.dataType : undefined,\n primary: typeof raw.primary === \"boolean\" ? raw.primary : undefined\n };\n}\n\nexport function getCollectionByPath(collectionPath: string, registry: PostgresCollectionRegistry): EntityCollection {\n const collection = registry.getCollectionByPath(collectionPath);\n if (!collection) {\n const registered = registry.getCollections().map(c => c.slug).join(\", \");\n throw new Error(`Collection not found: ${collectionPath}. Registered collections: [${registered}]`);\n }\n return collection;\n}\n\nexport function getTableForCollection(collection: EntityCollection, registry: PostgresCollectionRegistry): PgTable<any> {\n const tableName = getTableName(collection);\n const table = registry.getTable(tableName);\n if (!table) {\n throw new Error(`Table not found for collection '${collection.slug}' (table: ${tableName})`);\n }\n return table;\n}\n\nexport function getPrimaryKeys(collection: EntityCollection, registry: PostgresCollectionRegistry): { fieldName: string; type: \"string\" | \"number\"; isUUID?: boolean }[] {\n const table = getTableForCollection(collection, registry);\n\n // Fallback to explicitly defined isId properties\n if (collection.properties) {\n const idProps = Object.entries(collection.properties)\n .filter(([_, prop]) => \"isId\" in (prop as object) && Boolean((prop as { isId?: unknown }).isId))\n .map(([key, prop]) => ({\n fieldName: key,\n type: prop.type === \"number\" ? \"number\" as const : \"string\" as const,\n isUUID: (prop as { isId?: unknown }).isId === \"uuid\"\n }));\n\n if (idProps.length > 0) {\n return idProps;\n }\n }\n\n // Otherwise infer from Drizzle schema\n const keys: { fieldName: string; type: \"string\" | \"number\"; isUUID?: boolean }[] = [];\n for (const [key, colRaw] of Object.entries(table)) {\n const col = colRaw as AnyPgColumn;\n if (col && typeof col === \"object\" && \"primary\" in col && col.primary) {\n const meta = getColumnMeta(col);\n const type = col.dataType === \"number\" || meta.columnType === \"PgSerial\" || meta.columnType === \"PgInteger\" ? \"number\" : \"string\";\n const isUUID = meta.columnType === \"PgUUID\";\n keys.push({ fieldName: key,\ntype,\nisUUID });\n }\n }\n\n // Default to 'id' if no primary keys are found and it exists in the schema\n // This maintains backwards compatibility\n if (keys.length === 0 && \"id\" in table) {\n const idCol = table[\"id\" as keyof typeof table] as AnyPgColumn;\n const idMeta = getColumnMeta(idCol);\n const type = idCol.dataType === \"number\" || idMeta.columnType === \"PgSerial\" || idMeta.columnType === \"PgInteger\" ? \"number\" : \"string\";\n const isUUID = idMeta.columnType === \"PgUUID\";\n keys.push({ fieldName: \"id\",\ntype,\nisUUID });\n }\n\n return keys;\n}\n\nexport function parseIdValues(idValue: string | number, primaryKeys: { fieldName: string; type: \"string\" | \"number\"; isUUID?: boolean }[]): Record<string, string | number> {\n const result: Record<string, string | number> = {};\n\n if (primaryKeys.length === 0) {\n return result;\n }\n\n if (primaryKeys.length === 1) {\n const pk = primaryKeys[0];\n if (pk.type === \"number\" && !pk.isUUID) {\n const parsed = typeof idValue === \"number\" ? idValue : parseInt(String(idValue), 10);\n if (isNaN(parsed)) {\n throw new Error(`Invalid numeric ID: ${idValue}`);\n }\n result[pk.fieldName] = parsed;\n } else {\n result[pk.fieldName] = String(idValue);\n }\n return result;\n }\n\n // Composite key - split by :::\n const parts = String(idValue).split(\":::\");\n if (parts.length !== primaryKeys.length) {\n throw new Error(`Composite ID parts mismatch. Expected ${primaryKeys.length}, got ${parts.length} for ID: ${idValue}`);\n }\n\n for (let i = 0; i < primaryKeys.length; i++) {\n const pk = primaryKeys[i];\n const val = parts[i];\n if (pk.type === \"number\" && !pk.isUUID) {\n const parsed = parseInt(val, 10);\n if (isNaN(parsed)) {\n throw new Error(`Invalid numeric ID component: ${val}`);\n }\n result[pk.fieldName] = parsed;\n } else {\n result[pk.fieldName] = val;\n }\n }\n\n return result;\n}\n\nexport function buildCompositeId(values: Record<string, unknown>, primaryKeys: { fieldName: string; type: \"string\" | \"number\"; isUUID?: boolean }[]): string {\n if (primaryKeys.length === 0) {\n return \"\";\n }\n if (primaryKeys.length === 1) {\n return String(values[primaryKeys[0].fieldName] ?? \"\");\n }\n return primaryKeys.map(pk => String(values[pk.fieldName] ?? \"\")).join(\":::\");\n}\n","import { and, eq, or, sql, SQL, ilike, inArray } from \"drizzle-orm\";\nimport { AnyPgColumn, PgTable, PgVarchar, PgText, PgChar } from \"drizzle-orm/pg-core\";\nimport { FilterValues, WhereFilterOp, Relation, JoinStep, LogicalCondition, FilterCondition } from \"@rebasepro/types\";\nimport { getColumnName, resolveCollectionRelations } from \"@rebasepro/common\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { ConditionBuilderStatic } from \"../interfaces\";\nimport { logger } from \"@rebasepro/server-core\";\nimport { getColumnMeta } from \"../services/entity-helpers\";\n\n/** Drizzle dynamic query builder — accepts innerJoin + where chaining */\n\nexport interface DrizzleDynamicQuery {\n innerJoin(table: PgTable<any>, condition: SQL): this;\n where(condition: SQL | undefined): this;\n limit(limit: number): this;\n}\n\n/**\n * Unified condition builder for Drizzle/PostgreSQL queries.\n *\n * This class uses static methods and satisfies the ConditionBuilderStatic<SQL> type.\n * It translates Rebase filter conditions to Drizzle SQL conditions.\n *\n * @example\n * const builder: ConditionBuilderStatic<SQL> = DrizzleConditionBuilder;\n */\nexport class DrizzleConditionBuilder {\n\n /**\n * Build filter conditions from FilterValues\n */\n static buildFilterConditions<M extends Record<string, unknown>>(\n filter: FilterValues<Extract<keyof M, string>>,\n table: PgTable<any>,\n collectionPath: string\n ): SQL[] {\n const conditions: SQL[] = [];\n\n for (const [field, filterParam] of Object.entries(filter)) {\n if (!filterParam) continue;\n\n let fieldColumn = table[field as keyof typeof table] as AnyPgColumn;\n\n if (!fieldColumn) {\n // Fallback for relations (e.g. project -> project_id)\n const relationKey = `${field}_id`;\n if (relationKey in table) {\n fieldColumn = table[relationKey as keyof typeof table] as AnyPgColumn;\n }\n }\n\n if (!fieldColumn) {\n logger.warn(`Filtering by field '${field}', but it does not exist in table for collection '${collectionPath}'`);\n continue;\n }\n\n const paramsList = Array.isArray(filterParam) && filterParam.length > 0 && Array.isArray(filterParam[0])\n ? (filterParam as [WhereFilterOp, any][])\n : [filterParam as [WhereFilterOp, any]];\n\n for (const [op, value] of paramsList) {\n const condition = this.buildSingleFilterCondition(fieldColumn, op, value);\n if (condition) {\n conditions.push(condition);\n }\n }\n }\n\n return conditions;\n }\n\n /**\n * Build logical conditions recursively from LogicalCondition or FilterCondition\n */\n static buildLogicalConditions(\n cond: LogicalCondition | FilterCondition,\n table: PgTable<any>,\n collectionPath: string\n ): SQL | null {\n if (\"type\" in cond) {\n const subSQLs = cond.conditions\n .map(c => this.buildLogicalConditions(c, table, collectionPath))\n .filter((sql): sql is SQL => sql !== null);\n if (subSQLs.length === 0) return null;\n return (cond.type === \"or\" ? or(...subSQLs) : and(...subSQLs)) ?? null;\n } else {\n let fieldColumn = table[cond.column as keyof typeof table] as AnyPgColumn;\n if (!fieldColumn) {\n const relationKey = `${cond.column}_id`;\n if (relationKey in table) {\n fieldColumn = table[relationKey as keyof typeof table] as AnyPgColumn;\n }\n }\n if (!fieldColumn) {\n logger.warn(`Filtering by field '${cond.column}', but it does not exist in table for collection '${collectionPath}'`);\n return null;\n }\n return this.buildSingleFilterCondition(fieldColumn, cond.operator as WhereFilterOp, cond.value);\n }\n }\n\n /**\n * Build a single filter condition for a specific operator and value\n */\n static buildSingleFilterCondition(\n column: AnyPgColumn,\n op: WhereFilterOp,\n value: unknown\n ): SQL | null {\n switch (op) {\n case \"==\":\n if (value === null || value === undefined) {\n return sql`${column} IS NULL`;\n }\n return eq(column, value);\n case \"!=\":\n if (value === null || value === undefined) {\n return sql`${column} IS NOT NULL`;\n }\n return sql`${column} != ${value}`;\n case \">\":\n return sql`${column} > ${value}`;\n case \">=\":\n return sql`${column} >= ${value}`;\n case \"<\":\n return sql`${column} < ${value}`;\n case \"<=\":\n return sql`${column} <= ${value}`;\n case \"in\":\n if (Array.isArray(value) && value.length > 0) {\n return inArray(column, value);\n }\n return null;\n case \"array-contains\": {\n const meta = getColumnMeta(column);\n if (meta.dataType === \"array\" || meta.columnType === \"PgArray\") {\n return sql`${column} @> ARRAY[${value}]`;\n }\n // For JSONB arrays: checks if the column contains the given value\n return sql`${column} @> ${JSON.stringify([value])}`;\n }\n case \"array-contains-any\": {\n const meta = getColumnMeta(column);\n const isNativeArray = meta.dataType === \"array\" || meta.columnType === \"PgArray\";\n if (Array.isArray(value) && value.length > 0) {\n if (isNativeArray) {\n return sql`${column} && ARRAY[${sql.join(value.map(v => sql`${v}`), sql`, `)}]`;\n } else {\n // Use the ?| operator for JSONB overlap with text array\n const textValues = value.map(v => String(v));\n return sql`${column} ?| array[${sql.join(textValues.map(v => sql`${v}`), sql`, `)}]`;\n }\n }\n // Single value fallback: treat as array-contains\n if (isNativeArray) {\n return sql`${column} @> ARRAY[${value}]`;\n }\n return sql`${column} @> ${JSON.stringify([value])}`;\n }\n case \"not-in\":\n if (Array.isArray(value) && value.length > 0) {\n return sql`${column} NOT IN (${sql.join(value.map(v => sql`${v}`), sql`, `)})`;\n }\n return null;\n default:\n logger.warn(`Unsupported filter operation: ${op}`);\n return null;\n }\n }\n\n /**\n * Build relation-based conditions for different relation types\n */\n static buildRelationConditions(\n relation: Relation,\n parentEntityId: string | number | (string | number)[],\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentIdColumn: AnyPgColumn,\n targetIdColumn: AnyPgColumn,\n registry: PostgresCollectionRegistry\n ): {\n joinConditions: { table: PgTable<any>; condition: SQL }[];\n whereConditions: SQL[];\n } {\n console.debug(\"🔍 [buildRelationConditions] Building conditions for relation:\", {\n relationName: relation.relationName,\n cardinality: relation.cardinality,\n direction: relation.direction,\n hasThrough: !!relation.through,\n hasForeignKeyOnTarget: !!relation.foreignKeyOnTarget,\n inverseRelationName: relation.inverseRelationName,\n parentEntityId: parentEntityId\n });\n\n const joinConditions: { table: PgTable<any>; condition: SQL }[] = [];\n const whereConditions: SQL[] = [];\n\n if (relation.joinPath && relation.joinPath.length > 0) {\n console.debug(\"🔍 [buildRelationConditions] Using joinPath logic\");\n // Handle join path relations\n const {\n joins,\n finalCondition\n } = this.buildJoinPathConditions(\n relation.joinPath,\n targetTable,\n parentTable,\n parentIdColumn,\n parentEntityId,\n registry\n );\n joinConditions.push(...joins);\n whereConditions.push(finalCondition);\n\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"owning\") {\n console.debug(\"🔍 [buildRelationConditions] Using owning many-to-many with explicit through\");\n // Handle many-to-many relations with junction table\n const junctionResult = this.buildJunctionTableConditions(\n relation.through,\n targetIdColumn,\n parentEntityId,\n registry\n );\n joinConditions.push(junctionResult.join);\n whereConditions.push(junctionResult.condition);\n\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"inverse\") {\n console.debug(\"🔍 [buildRelationConditions] Using inverse many-to-many with explicit through\");\n // Handle inverse many-to-many relations with junction table\n const junctionResult = this.buildInverseJunctionTableConditions(\n relation.through,\n targetIdColumn,\n parentEntityId,\n registry\n );\n joinConditions.push(junctionResult.join);\n whereConditions.push(junctionResult.condition);\n\n } else if (relation.cardinality === \"many\" && relation.direction === \"inverse\" && !relation.through) {\n console.debug(\"🔍 [buildRelationConditions] Handling inverse many relationship without explicit through\");\n\n // First, try to find a junction table (for many-to-many relationships)\n const junctionInfo = this.findCorrespondingJunctionTable(relation, registry);\n if (junctionInfo) {\n console.debug(\"🔍 [buildRelationConditions] Found junction info for inverse many-to-many, building junction conditions\");\n const junctionResult = this.buildInverseJunctionTableConditions(\n junctionInfo,\n targetIdColumn,\n parentEntityId,\n registry\n );\n joinConditions.push(junctionResult.join);\n whereConditions.push(junctionResult.condition);\n } else if (relation.foreignKeyOnTarget) {\n console.debug(\"🔍 [buildRelationConditions] No junction table found, treating as inverse one-to-many with foreign key on target\");\n // This is a true inverse one-to-many relationship\n const simpleCondition = this.buildSimpleRelationCondition(\n relation,\n targetTable,\n parentTable,\n parentEntityId\n );\n whereConditions.push(simpleCondition);\n } else {\n logger.error(\"🔍 [buildRelationConditions] Failed to find junction table info and no foreign key specified\");\n throw new Error(`Cannot resolve inverse many relation '${relation.relationName}'. Either specify 'through' property, ensure corresponding owning relation exists with junction table configuration, or specify 'foreignKeyOnTarget' for one-to-many relationships.`);\n }\n } else {\n console.debug(\"🔍 [buildRelationConditions] Using simple relation logic - THIS IS WHERE THE ERROR MIGHT OCCUR\");\n // Handle simple relations\n const simpleCondition = this.buildSimpleRelationCondition(\n relation,\n targetTable,\n parentTable,\n parentEntityId\n );\n whereConditions.push(simpleCondition);\n }\n\n console.debug(\"🔍 [buildRelationConditions] Final result:\", {\n joinConditionsCount: joinConditions.length,\n whereConditionsCount: whereConditions.length\n });\n\n return {\n joinConditions,\n whereConditions\n };\n }\n\n /**\n * Build conditions for join path relations\n */\n private static buildJoinPathConditions(\n joinPath: JoinStep[],\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentIdColumn: AnyPgColumn,\n parentEntityId: string | number | (string | number)[],\n registry: PostgresCollectionRegistry\n ): {\n joins: { table: PgTable<any>; condition: SQL }[];\n finalCondition: SQL;\n } {\n const joins: { table: PgTable<any>; condition: SQL }[] = [];\n let currentTable = targetTable;\n\n // Process join steps in reverse order to build path back to parent\n for (const joinStep of [...joinPath].reverse()) {\n const fromTableName = this.getTableNamesFromColumns(joinStep.on.from)[0];\n const toTableName = this.getTableNamesFromColumns(joinStep.on.to)[0];\n const fromColName = this.getColumnNamesFromColumns(joinStep.on.from)[0];\n const toColName = this.getColumnNamesFromColumns(joinStep.on.to)[0];\n\n const fromTable = registry.getTable(fromTableName);\n const toTable = registry.getTable(toTableName);\n\n if (!fromTable || !toTable) {\n throw new Error(`Join tables not found for step: from ${fromTableName} to ${toTableName}`);\n }\n\n const {\n joinTable,\n condition,\n additionalJoins\n } = this.buildSingleJoinCondition(\n currentTable,\n fromTable,\n toTable,\n fromColName,\n toColName,\n fromTableName,\n toTableName,\n registry\n );\n\n joins.push({\n table: joinTable,\n condition\n });\n currentTable = joinTable;\n\n // Add any additional joins needed for many-to-many relationships\n if (additionalJoins && additionalJoins.length > 0) {\n joins.push(...additionalJoins);\n }\n }\n\n // Ensure we've connected back to the parent table\n // For junction tables, we might end up at the junction table instead of the parent table\n if (currentTable !== parentTable) {\n // Try to get table names from the Drizzle table objects\n let currentTableName = \"unknown\";\n let parentTableName = \"unknown\";\n\n // Try multiple ways to extract table names from Drizzle objects\n if (currentTable && typeof currentTable === \"object\") {\n // Check common Drizzle table name properties\n currentTableName = (currentTable as unknown as Record<string | symbol, unknown>)[Symbol.for(\"drizzle:Name\")] as string ||\n ((currentTable as unknown as Record<string, unknown>)._ as Record<string, unknown>)?.name as string ||\n (currentTable as unknown as Record<string, unknown>).tableName as string ||\n (currentTable as unknown as Record<string, unknown>).name as string ||\n \"unknown\";\n }\n\n if (parentTable && typeof parentTable === \"object\") {\n parentTableName = (parentTable as unknown as Record<string | symbol, unknown>)[Symbol.for(\"drizzle:Name\")] as string ||\n ((parentTable as unknown as Record<string, unknown>)._ as Record<string, unknown>)?.name as string ||\n (parentTable as unknown as Record<string, unknown>).tableName as string ||\n (parentTable as unknown as Record<string, unknown>).name as string ||\n \"unknown\";\n }\n\n // For junction table scenarios, be more lenient with validation\n // If we can't determine table names reliably, or if this looks like a junction table scenario,\n // we'll allow it and let the SQL execution validate the correctness\n const couldBeJunctionScenario = currentTableName.includes(\"_\") ||\n currentTableName === \"unknown\" ||\n parentTableName === \"unknown\";\n\n if (!couldBeJunctionScenario) {\n throw new Error(`Join path did not result in connecting to parent table. Current: ${currentTableName}, Parent: ${parentTableName}`);\n }\n }\n\n // Handle both single ID and array of IDs\n const finalCondition = Array.isArray(parentEntityId)\n ? inArray(parentIdColumn, parentEntityId)\n : eq(parentIdColumn, parentEntityId);\n\n return {\n joins,\n finalCondition\n };\n }\n\n /**\n * Build a single join condition between tables\n */\n private static buildSingleJoinCondition(\n currentTable: PgTable<any>,\n fromTable: PgTable<any>,\n toTable: PgTable<any>,\n fromColName: string,\n toColName: string,\n fromTableName: string,\n toTableName: string,\n registry?: PostgresCollectionRegistry\n ): { joinTable: PgTable<any>; condition: SQL; additionalJoins?: { table: PgTable<any>; condition: SQL }[] } {\n let joinTable: PgTable<any>;\n let condition: SQL;\n const additionalJoins: { table: PgTable<any>; condition: SQL }[] = [];\n\n if (currentTable === toTable) {\n // current -> toTable, so join the fromTable\n const left = fromTable[fromColName as keyof typeof fromTable] as AnyPgColumn;\n const right = (currentTable as unknown as Record<string, unknown>)[toColName] as AnyPgColumn;\n\n if (!left || !right) {\n // Check if this might be a many-to-many relationship requiring a junction table\n if (registry) {\n const junctionResult = this.tryBuildJunctionJoin(\n currentTable,\n fromTable,\n fromColName,\n toColName,\n fromTableName,\n toTableName,\n registry\n );\n if (junctionResult) {\n return junctionResult;\n }\n }\n throw new Error(`Join columns not found: ${fromTableName}.${fromColName} = ${toTableName}.${toColName}`);\n }\n\n joinTable = fromTable;\n condition = eq(left, right);\n } else if (currentTable === fromTable) {\n // current -> fromTable, so join the toTable\n const left = toTable[toColName as keyof typeof toTable] as AnyPgColumn;\n const right = (currentTable as unknown as Record<string, unknown>)[fromColName] as AnyPgColumn;\n\n if (!left || !right) {\n // Check if this might be a many-to-many relationship requiring a junction table\n if (registry) {\n const junctionResult = this.tryBuildJunctionJoin(\n currentTable,\n toTable,\n fromColName,\n toColName,\n fromTableName,\n toTableName,\n registry\n );\n if (junctionResult) {\n return junctionResult;\n }\n }\n throw new Error(`Join columns not found: ${toTableName}.${toColName} = ${fromTableName}.${fromColName}`);\n }\n\n joinTable = toTable;\n condition = eq(left, right);\n } else {\n throw new Error(`Join step does not match current table. Current table does not match from: ${fromTableName} or to: ${toTableName}`);\n }\n\n return {\n joinTable,\n condition,\n additionalJoins\n };\n }\n\n /**\n * Try to build a junction table join when direct foreign key relationship is not found\n */\n private static tryBuildJunctionJoin(\n currentTable: PgTable<any>,\n targetTable: PgTable<any>,\n fromColName: string,\n toColName: string,\n fromTableName: string,\n toTableName: string,\n registry: PostgresCollectionRegistry\n ): { joinTable: PgTable<any>; condition: SQL; additionalJoins: { table: PgTable<any>; condition: SQL }[] } | null {\n // Try to find a junction table that connects these two tables\n // Common naming patterns: table1_table2, table1Table2, etc.\n const possibleJunctionNames = [\n `${fromTableName}_${toTableName}`,\n `${toTableName}_${fromTableName}`,\n `${fromTableName}${toTableName.charAt(0).toUpperCase() + toTableName.slice(1)}`,\n `${toTableName}${fromTableName.charAt(0).toUpperCase() + fromTableName.slice(1)}`\n ];\n\n for (const junctionName of possibleJunctionNames) {\n const junctionTable = registry.getTable(junctionName);\n if (junctionTable) {\n // Try to find the appropriate columns in the junction table\n const sourceColName = `${fromTableName.slice(0, -1)}_id`; // Remove 's' and add '_id'\n const targetColName = `${toTableName.slice(0, -1)}_id`;\n\n const junctionSourceCol = junctionTable[sourceColName as keyof typeof junctionTable] as AnyPgColumn;\n const junctionTargetCol = junctionTable[targetColName as keyof typeof junctionTable] as AnyPgColumn;\n\n if (junctionSourceCol && junctionTargetCol) {\n // Found a valid junction table setup\n const currentTableIdCol = Object.values(currentTable).find((col: Record<string, unknown>) => col.primary) as AnyPgColumn;\n const targetTableIdCol = Object.values(targetTable).find((col: Record<string, unknown>) => col.primary) as AnyPgColumn;\n\n if (!currentTableIdCol || !targetTableIdCol) {\n continue; // Skip if we can't find primary keys\n }\n\n // Determine which direction to join\n if (currentTable === targetTable) {\n // We're joining through junction to reach the other table\n return {\n joinTable: targetTable,\n condition: eq(targetTableIdCol, junctionTargetCol),\n additionalJoins: [\n {\n table: junctionTable,\n condition: eq(currentTableIdCol, junctionSourceCol)\n }\n ]\n };\n } else {\n // Standard junction join\n return {\n joinTable: junctionTable,\n condition: eq(currentTableIdCol, junctionSourceCol),\n additionalJoins: [\n {\n table: targetTable,\n condition: eq(targetTableIdCol, junctionTargetCol)\n }\n ]\n };\n }\n }\n }\n }\n\n return null; // No junction table found\n }\n\n /**\n * Build conditions for junction table (many-to-many) relations\n */\n private static buildJunctionTableConditions(\n through: { table: string; sourceColumn: string; targetColumn: string },\n targetIdColumn: AnyPgColumn,\n parentEntityId: string | number | (string | number)[],\n registry: PostgresCollectionRegistry\n ): { join: { table: PgTable<any>; condition: SQL }; condition: SQL } {\n const junctionTable = registry.getTable(through.table);\n if (!junctionTable) {\n throw new Error(`Junction table not found: ${through.table}`);\n }\n\n const junctionSourceCol = junctionTable[through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const junctionTargetCol = junctionTable[through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!junctionSourceCol) {\n throw new Error(`Source column '${through.sourceColumn}' not found in junction table '${through.table}'`);\n }\n if (!junctionTargetCol) {\n throw new Error(`Target column '${through.targetColumn}' not found in junction table '${through.table}'`);\n }\n\n // Handle both single ID and array of IDs\n const condition = Array.isArray(parentEntityId)\n ? inArray(junctionSourceCol, parentEntityId)\n : eq(junctionSourceCol, parentEntityId);\n\n return {\n join: {\n table: junctionTable,\n condition: eq(targetIdColumn, junctionTargetCol)\n },\n condition\n };\n }\n\n /**\n * Build conditions for inverse junction table (many-to-many) relations\n */\n private static buildInverseJunctionTableConditions(\n through: { table: string; sourceColumn: string; targetColumn: string },\n targetIdColumn: AnyPgColumn,\n parentEntityId: string | number | (string | number)[],\n registry: PostgresCollectionRegistry\n ): { join: { table: PgTable<any>; condition: SQL }; condition: SQL } {\n const junctionTable = registry.getTable(through.table);\n if (!junctionTable) {\n throw new Error(`Junction table not found: ${through.table}`);\n }\n\n const junctionSourceCol = junctionTable[through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const junctionTargetCol = junctionTable[through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!junctionSourceCol) {\n throw new Error(`Source column '${through.sourceColumn}' not found in junction table '${through.table}'`);\n }\n if (!junctionTargetCol) {\n throw new Error(`Target column '${through.targetColumn}' not found in junction table '${through.table}'`);\n }\n\n // For inverse relations, the parentEntityId (tag ID) should match the sourceColumn (tag_id)\n // and we want to find target entities (posts) through the targetColumn (post_id)\n const condition = Array.isArray(parentEntityId)\n ? inArray(junctionSourceCol, parentEntityId)\n : eq(junctionSourceCol, parentEntityId);\n\n return {\n join: {\n table: junctionTable,\n condition: eq(targetIdColumn, junctionTargetCol)\n },\n condition\n };\n }\n\n /**\n * Build conditions for simple relations (owning/inverse without join paths)\n */\n private static buildSimpleRelationCondition(\n relation: Relation,\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentEntityId: string | number | (string | number)[]\n ): SQL {\n if (relation.direction === \"owning\" && relation.localKey) {\n // For owning relations, the parentEntityId is actually the foreign key value\n // that should match the target table's primary key\n const targetIdCol = Object.values(targetTable).find((col: Record<string, unknown>) => col.primary) as AnyPgColumn;\n if (!targetIdCol) {\n // Fallback to looking for an \"id\" column by name\n const idCol = Object.values(targetTable).find((col: Record<string, unknown>) => col.name === \"id\") as AnyPgColumn;\n if (!idCol) {\n throw new Error(\"No primary key or \\\"id\\\" column found in target table\");\n }\n return Array.isArray(parentEntityId)\n ? inArray(idCol, parentEntityId)\n : eq(idCol, parentEntityId);\n }\n return Array.isArray(parentEntityId)\n ? inArray(targetIdCol, parentEntityId)\n : eq(targetIdCol, parentEntityId);\n\n } else if (relation.direction === \"inverse\" && relation.foreignKeyOnTarget) {\n // Inverse relation: use foreign key on target table\n const foreignKeyCol = targetTable[relation.foreignKeyOnTarget as keyof typeof targetTable] as AnyPgColumn;\n if (!foreignKeyCol) {\n // This could be a many-to-many relationship where foreignKeyOnTarget was set by sanitizeRelation\n // but the column doesn't actually exist. In this case, we should suggest using junction tables.\n throw new Error(`Foreign key column '${relation.foreignKeyOnTarget}' not found in target table. This might be a many-to-many relationship that requires a junction table. Consider using 'through' property or ensure the corresponding owning relation exists with junction table configuration.`);\n }\n return Array.isArray(parentEntityId)\n ? inArray(foreignKeyCol, parentEntityId)\n : eq(foreignKeyCol, parentEntityId);\n\n } else if (relation.direction === \"inverse\" && relation.cardinality === \"many\" && relation.inverseRelationName) {\n // For inverse many-to-many relations, this should not be called directly\n // The buildRelationConditions method should handle finding the junction table\n // If we reach here, it means the junction table lookup failed\n throw new Error(`Inverse many-to-many relation '${relation.relationName}' requires a junction table. Either specify 'through' property or ensure the corresponding owning relation exists with junction table configuration.`);\n\n } else if (relation.direction === \"inverse\" && relation.cardinality === \"one\" && relation.inverseRelationName) {\n // Auto-infer foreign key column for inverse one-to-one relations\n // Pattern: {inverseRelationName}_id (e.g., \"author\" -> \"author_id\")\n const inferredForeignKeyName = `${relation.inverseRelationName}_id`;\n const foreignKeyCol = targetTable[inferredForeignKeyName as keyof typeof targetTable] as AnyPgColumn;\n\n if (!foreignKeyCol) {\n throw new Error(`Auto-inferred foreign key column '${inferredForeignKeyName}' not found in target table for inverse relation '${relation.relationName}'. Please specify 'foreignKeyOnTarget' explicitly.`);\n }\n\n console.debug(`🔍 [DrizzleConditionBuilder] Auto-inferred foreign key '${inferredForeignKeyName}' for inverse relation '${relation.relationName}'`);\n\n return Array.isArray(parentEntityId)\n ? inArray(foreignKeyCol, parentEntityId)\n : eq(foreignKeyCol, parentEntityId);\n\n } else {\n throw new Error(`Relation '${relation.relationName}' lacks proper configuration. For many-to-many relations, use 'through' property. For simple relations, use 'localKey' or 'foreignKeyOnTarget'.`);\n }\n }\n\n /**\n * Combine multiple conditions with AND operator\n */\n static combineConditionsWithAnd(conditions: SQL[]): SQL | 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 static combineConditionsWithOr(conditions: SQL[]): SQL | 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 search conditions for text fields\n */\n static buildSearchConditions(\n searchString: string,\n properties: Record<string, unknown>,\n table: PgTable<any>\n ): SQL[] {\n const searchConditions: SQL[] = [];\n\n for (const [key, prop] of Object.entries(properties)) {\n const p = prop as Record<string, unknown>;\n // Only include string properties that don't have enum defined\n // PostgreSQL enum and uuid columns don't support ILIKE, so we skip them\n if (p.type === \"string\" && !p.enum && p.isId !== \"uuid\") {\n const fieldColumn = table[key as keyof typeof table] as AnyPgColumn;\n if (fieldColumn) {\n // Verify that the underlying database column supports string pattern-matching\n const supportsILike =\n fieldColumn instanceof PgVarchar ||\n fieldColumn instanceof PgText ||\n fieldColumn instanceof PgChar ||\n (fieldColumn && typeof fieldColumn === \"object\" && !(\"columnType\" in fieldColumn));\n if (supportsILike) {\n searchConditions.push(ilike(fieldColumn, `%${searchString}%`));\n }\n }\n }\n }\n\n return searchConditions;\n }\n\n /**\n * Build a unique field check condition\n */\n static buildUniqueFieldCondition(\n fieldColumn: AnyPgColumn,\n value: unknown,\n idColumn?: AnyPgColumn,\n excludeId?: string | number\n ): SQL[] {\n const conditions: SQL[] = [eq(fieldColumn, value)];\n\n if (excludeId && idColumn) {\n conditions.push(sql`${idColumn} != ${excludeId}`);\n }\n\n return conditions;\n }\n\n /**\n * Build relation-based query with joins and conditions\n */\n static buildRelationQuery<T extends DrizzleDynamicQuery>(\n baseQuery: T,\n relation: Relation,\n parentEntityId: string | number | (string | number)[],\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentIdColumn: AnyPgColumn,\n targetIdColumn: AnyPgColumn,\n registry: PostgresCollectionRegistry,\n additionalFilters?: SQL[]\n ): T {\n const { joinConditions, whereConditions } = this.buildRelationConditions(\n relation,\n parentEntityId,\n targetTable,\n parentTable,\n parentIdColumn,\n targetIdColumn,\n registry\n );\n\n let query = baseQuery;\n\n // Apply joins\n for (const { table, condition } of joinConditions) {\n query = query.innerJoin(table, condition);\n }\n\n // Combine all conditions\n const allConditions = [...whereConditions];\n if (additionalFilters) {\n allConditions.push(...additionalFilters);\n }\n\n // Apply where conditions\n if (allConditions.length > 0) {\n query = query.where(and(...allConditions));\n }\n\n return query;\n }\n\n /**\n * Build count query for relations with proper joins and conditions\n */\n static buildRelationCountQuery<T extends DrizzleDynamicQuery>(\n baseCountQuery: T,\n relation: Relation,\n parentEntityId: string | number,\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentIdColumn: AnyPgColumn,\n targetIdColumn: AnyPgColumn,\n registry: PostgresCollectionRegistry,\n additionalFilters?: SQL[]\n ): T {\n // For count queries, we need to handle joins differently to avoid duplicates\n if (relation.joinPath && relation.joinPath.length > 0) {\n return this.buildJoinPathCountQuery(\n baseCountQuery,\n relation.joinPath,\n targetTable,\n parentTable,\n parentIdColumn,\n parentEntityId,\n registry,\n additionalFilters\n );\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"owning\") {\n return this.buildJunctionCountQuery(\n baseCountQuery,\n relation.through,\n targetIdColumn,\n parentEntityId,\n registry,\n additionalFilters\n );\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"inverse\") {\n return this.buildInverseJunctionCountQuery(\n baseCountQuery,\n relation.through,\n targetIdColumn,\n parentEntityId,\n registry,\n additionalFilters\n );\n } else {\n // Simple relations\n const simpleCondition = this.buildSimpleRelationCondition(\n relation,\n targetTable,\n parentTable,\n parentEntityId\n );\n\n const allConditions = [simpleCondition];\n if (additionalFilters) {\n allConditions.push(...additionalFilters);\n }\n\n return baseCountQuery.where(and(...allConditions));\n }\n }\n\n /**\n * Build join path conditions for count queries\n */\n private static buildJoinPathCountQuery<T extends DrizzleDynamicQuery>(\n baseCountQuery: T,\n joinPath: JoinStep[],\n targetTable: PgTable<any>,\n parentTable: PgTable<any>,\n parentIdColumn: AnyPgColumn,\n parentEntityId: string | number,\n registry: PostgresCollectionRegistry,\n additionalFilters?: SQL[]\n ): T {\n let query = baseCountQuery;\n let currentTable = targetTable;\n\n // Process join steps in reverse order\n for (const joinStep of [...joinPath].reverse()) {\n const fromTableName = this.getTableNamesFromColumns(joinStep.on.from)[0];\n const toTableName = this.getTableNamesFromColumns(joinStep.on.to)[0];\n const fromColName = this.getColumnNamesFromColumns(joinStep.on.from)[0];\n const toColName = this.getColumnNamesFromColumns(joinStep.on.to)[0];\n\n const fromTable = registry.getTable(fromTableName);\n const toTable = registry.getTable(toTableName);\n\n if (!fromTable || !toTable) {\n throw new Error(`Join tables not found for step: from ${fromTableName} to ${toTableName}`);\n }\n\n const { joinTable, condition } = this.buildSingleJoinCondition(\n currentTable,\n fromTable,\n toTable,\n fromColName,\n toColName,\n fromTableName,\n toTableName\n );\n\n query = query.innerJoin(joinTable, condition);\n currentTable = joinTable;\n }\n\n if (currentTable !== parentTable) {\n throw new Error(\"Join path did not result in connecting to parent table\");\n }\n\n const allConditions = [eq(parentIdColumn, parentEntityId)];\n if (additionalFilters) {\n allConditions.push(...additionalFilters);\n }\n\n return query.where(and(...allConditions));\n }\n\n /**\n * Build junction table conditions for count queries\n */\n private static buildJunctionCountQuery<T extends DrizzleDynamicQuery>(\n baseCountQuery: T,\n through: { table: string; sourceColumn: string; targetColumn: string },\n targetIdColumn: AnyPgColumn,\n parentEntityId: string | number,\n registry: PostgresCollectionRegistry,\n additionalFilters?: SQL[]\n ): T {\n const junctionTable = registry.getTable(through.table);\n if (!junctionTable) {\n throw new Error(`Junction table not found: ${through.table}`);\n }\n\n const junctionSourceCol = junctionTable[through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const junctionTargetCol = junctionTable[through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!junctionSourceCol) {\n throw new Error(`Source column '${through.sourceColumn}' not found in junction table '${through.table}'`);\n }\n if (!junctionTargetCol) {\n throw new Error(`Target column '${through.targetColumn}' not found in junction table '${through.table}'`);\n }\n\n const baseConditions = [eq(junctionSourceCol, parentEntityId)];\n if (additionalFilters && additionalFilters.length > 0) {\n baseConditions.push(...additionalFilters);\n }\n\n return baseCountQuery\n .innerJoin(junctionTable, eq(targetIdColumn, junctionTargetCol))\n .where(and(...baseConditions));\n }\n\n /**\n * Build inverse junction table conditions for count queries\n */\n private static buildInverseJunctionCountQuery<T extends DrizzleDynamicQuery>(\n baseCountQuery: T,\n through: { table: string; sourceColumn: string; targetColumn: string },\n targetIdColumn: AnyPgColumn,\n parentEntityId: string | number,\n registry: PostgresCollectionRegistry,\n additionalFilters?: SQL[]\n ): T {\n const junctionTable = registry.getTable(through.table);\n if (!junctionTable) {\n throw new Error(`Junction table not found: ${through.table}`);\n }\n\n const junctionSourceCol = junctionTable[through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const junctionTargetCol = junctionTable[through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!junctionSourceCol) {\n throw new Error(`Source column '${through.sourceColumn}' not found in junction table '${through.table}'`);\n }\n if (!junctionTargetCol) {\n throw new Error(`Target column '${through.targetColumn}' not found in junction table '${through.table}'`);\n }\n\n const baseConditions = [eq(junctionSourceCol, parentEntityId)];\n if (additionalFilters && additionalFilters.length > 0) {\n baseConditions.push(...additionalFilters);\n }\n\n return baseCountQuery\n .innerJoin(junctionTable, eq(targetIdColumn, junctionTargetCol))\n .where(and(...baseConditions));\n }\n\n /**\n * Helper method to extract table names from columns\n */\n static getTableNamesFromColumns(columns: string | string[]): string[] {\n if (Array.isArray(columns)) {\n return columns.map(col => col.includes(\".\") ? col.split(\".\")[0] : \"\");\n }\n return [columns.includes(\".\") ? columns.split(\".\")[0] : \"\"];\n }\n\n /**\n * Helper method to extract column names from columns\n */\n static getColumnNamesFromColumns(columns: string | string[]): string[] {\n if (Array.isArray(columns)) {\n return columns.map(col => getColumnName(col));\n }\n return [getColumnName(columns)];\n }\n\n /**\n * Find the corresponding junction table for an inverse many-to-many relation\n */\n private static findCorrespondingJunctionTable(\n relation: Relation,\n registry: PostgresCollectionRegistry\n ): { table: string; sourceColumn: string; targetColumn: string } | null {\n try {\n console.debug(`🔍 [findCorrespondingJunctionTable] Looking for junction table for inverse relation '${relation.relationName}' with inverseRelationName '${relation.inverseRelationName}'`);\n\n if (!relation.inverseRelationName) {\n console.debug(\"🔍 [findCorrespondingJunctionTable] No inverseRelationName specified\");\n return null;\n }\n\n // Get the target collection of the inverse relation\n const targetCollection = relation.target();\n console.debug(`🔍 [findCorrespondingJunctionTable] Target collection: ${targetCollection.slug}`);\n\n // Find the corresponding owning relation on the target collection\n const targetCollectionRelations = resolveCollectionRelations(targetCollection);\n console.debug(\"🔍 [findCorrespondingJunctionTable] Target collection relations:\", Object.keys(targetCollectionRelations));\n\n // Look for the owning many-to-many relation that matches our inverseRelationName\n const correspondingRelation = targetCollectionRelations[relation.inverseRelationName];\n\n if (!correspondingRelation) {\n console.debug(`🔍 [findCorrespondingJunctionTable] No relation found with key '${relation.inverseRelationName}' on target collection`);\n return null;\n }\n\n console.debug(\"🔍 [findCorrespondingJunctionTable] Found relation:\", {\n relationName: correspondingRelation.relationName,\n cardinality: correspondingRelation.cardinality,\n direction: correspondingRelation.direction,\n hasThrough: !!correspondingRelation.through\n });\n\n // Verify it's an owning many-to-many relation with junction table\n if (correspondingRelation.cardinality !== \"many\" ||\n correspondingRelation.direction !== \"owning\" ||\n !correspondingRelation.through) {\n console.debug(\"🔍 [findCorrespondingJunctionTable] Relation is not an owning many-to-many with junction table\");\n return null;\n }\n\n console.debug(\"🔍 [findCorrespondingJunctionTable] Found matching owning relation with junction table!\");\n\n // For inverse relation, we need to swap source and target columns\n const through = correspondingRelation.through;\n const result = {\n table: through.table,\n sourceColumn: through.targetColumn, // Swapped for inverse relation\n targetColumn: through.sourceColumn // Swapped for inverse relation\n };\n\n console.debug(\"🔍 [findCorrespondingJunctionTable] Returning junction info:\", result);\n return result;\n } catch (error) {\n logger.error(`🔍 [findCorrespondingJunctionTable] Error finding corresponding junction table for relation '${relation.relationName}'`, { error: error });\n return null;\n }\n }\n\n /**\n * Build vector similarity search expressions for pgvector.\n *\n * Returns:\n * - `orderBy`: SQL expression to ORDER BY distance (ascending = closest first)\n * - `filter`: optional WHERE clause for distance threshold\n * - `distanceSelect`: SQL expression for selecting the distance as `_distance`\n */\n static buildVectorSearchConditions(\n table: PgTable<any>,\n vectorSearch: {\n property: string;\n vector: number[];\n distance?: \"cosine\" | \"l2\" | \"inner_product\";\n threshold?: number;\n }\n ): { orderBy: SQL; filter?: SQL; distanceSelect: SQL } {\n const column = table[vectorSearch.property as keyof typeof table] as AnyPgColumn;\n if (!column) {\n throw new Error(`Vector column '${vectorSearch.property}' not found in table`);\n }\n\n const vectorLiteral = `'[${vectorSearch.vector.join(\",\")}]'::vector`;\n const distanceFn = vectorSearch.distance || \"cosine\";\n\n let operator: string;\n switch (distanceFn) {\n case \"cosine\":\n operator = \"<=>\";\n break;\n case \"l2\":\n operator = \"<->\";\n break;\n case \"inner_product\":\n operator = \"<#>\";\n break;\n }\n\n const distanceExpr = sql`${column} ${sql.raw(operator)} ${sql.raw(vectorLiteral)}`;\n\n return {\n orderBy: distanceExpr,\n filter: vectorSearch.threshold != null\n ? sql`(${column} ${sql.raw(operator)} ${sql.raw(vectorLiteral)}) < ${vectorSearch.threshold}`\n : undefined,\n distanceSelect: sql`(${column} ${sql.raw(operator)} ${sql.raw(vectorLiteral)})`\n };\n }\n}\n\n/**\n * Alias for DrizzleConditionBuilder for consistent naming with other database implementations.\n * This allows code to use PostgresConditionBuilder alongside future MongoConditionBuilder, etc.\n */\nexport const PostgresConditionBuilder = DrizzleConditionBuilder;\n\n","import { eq, SQL } from \"drizzle-orm\";\nimport { AnyPgColumn } from \"drizzle-orm/pg-core\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { CollectionWithRelations, EntityCollection, Properties, Property, Relation, RelationProperty, Vector, BinaryProperty } from \"@rebasepro/types\";\nimport { getTableName, resolveCollectionRelations, findRelation, createRelationRef, DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE } from \"@rebasepro/common\";\nimport { PostgresCollectionRegistry } from \"./collections/PostgresCollectionRegistry\";\nimport { DrizzleConditionBuilder } from \"./utils/drizzle-conditions\";\nimport { getPrimaryKeys, buildCompositeId } from \"./services/entity-helpers\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/**\n * Data transformation utilities for converting between frontend and database formats.\n */\n\n/**\n * Typed result from `serializeDataToServer`.\n * Replaces the hidden `__inverseRelationUpdates` / `__joinPathRelationUpdates`\n * dunder-property mutation pattern with explicit, typed state management.\n */\nexport interface SerializedEntityData {\n /** Scalar column values ready for INSERT/UPDATE. */\n scalarData: Record<string, unknown>;\n /** Inverse relation updates that must be applied to target tables. */\n inverseRelationUpdates: Array<{\n relationKey: string;\n relation: Relation;\n newValue: unknown;\n currentEntityId?: string | number;\n }>;\n /** JoinPath relation updates that require multi-hop writes. */\n joinPathRelationUpdates: Array<{\n relationKey: string;\n relation: Relation;\n newTargetId: string | number | null;\n }>;\n}\n/**\n * Helper function to sanitize and convert dates to ISO strings\n */\nexport function sanitizeAndConvertDates(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return null;\n }\n\n if (typeof obj === \"number\" && isNaN(obj)) {\n return null;\n }\n\n if (typeof obj === \"string\" && obj.toLowerCase() === \"nan\") {\n return null;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(v => sanitizeAndConvertDates(v));\n }\n\n if (obj instanceof Date) {\n return obj.toISOString();\n }\n\n if (typeof obj === \"object\") {\n const newObj: Record<string, unknown> = {};\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n newObj[key] = sanitizeAndConvertDates((obj as Record<string, unknown>)[key]);\n }\n }\n return newObj;\n }\n\n if (typeof obj === \"string\") {\n const isoDateRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z$/;\n const jsDateRegex = /^\\w{3} \\w{3} \\d{2} \\d{4} \\d{2}:\\d{2}:\\d{2} GMT[+-]\\d{4} \\(.+\\)$/;\n if (isoDateRegex.test(obj) || jsDateRegex.test(obj)) {\n const date = new Date(obj);\n if (!isNaN(date.getTime())) {\n return date.toISOString();\n }\n }\n }\n\n return obj;\n}\n\n/**\n * Transform relations for database storage (relation objects to IDs)\n */\nexport function serializeDataToServer<M extends Record<string, unknown>>(\n entity: M,\n properties: Properties,\n collection?: EntityCollection,\n registry?: PostgresCollectionRegistry\n): SerializedEntityData {\n if (!entity || !properties) return { scalarData: entity ?? {},\ninverseRelationUpdates: [],\njoinPathRelationUpdates: [] };\n\n const result: Record<string, unknown> = {};\n\n // Get normalized relations if collection is provided\n const resolvedRelations = collection ? resolveCollectionRelations(collection) : {};\n\n // Track inverse relations that need to be handled separately\n const inverseRelationUpdates: Array<{\n relationKey: string;\n relation: Relation;\n newValue: unknown;\n currentEntityId?: string | number;\n }> = [];\n const joinPathRelationUpdates: Array<{\n relationKey: string;\n relation: Relation;\n newTargetId: string | number | null;\n }> = [];\n\n // Pre-calculate all local keys used as foreign keys\n const foreignKeys = new Set<string>();\n Object.values(resolvedRelations).forEach(relation => {\n if (relation.localKey) foreignKeys.add(relation.localKey);\n });\n\n for (const [key, value] of Object.entries(entity)) {\n const property = properties[key as keyof M] as Property;\n\n // Coerce empty strings to null for any field that acts as a foreign key\n const effectiveValue = (foreignKeys.has(key) && value === \"\") ? null : value;\n\n if (!property) {\n result[key] = effectiveValue;\n continue;\n }\n\n\n // Handle relation properties specially\n if (property.type === \"relation\" && collection) {\n const relation = findRelation(resolvedRelations, key);\n if (relation) {\n if (relation.direction === \"owning\" && relation.localKey) {\n // Owning relation: Map relation object to FK column on current table\n const serializedValue = serializePropertyToServer(effectiveValue, property);\n if (serializedValue !== undefined) {\n result[relation.localKey] = serializedValue;\n }\n // Don't add the original relation property to the result\n continue;\n } else if (relation.direction === \"inverse\" && relation.foreignKeyOnTarget) {\n // Inverse relation: Need to update the target table's FK\n const serializedValue = serializePropertyToServer(effectiveValue, property);\n const pks = getPrimaryKeys(collection, registry!);\n inverseRelationUpdates.push({\n relationKey: key,\n relation,\n newValue: serializedValue,\n currentEntityId: (entity.id as string | number | undefined) || buildCompositeId(entity, pks)\n });\n // Don't add the original relation property to the result\n continue;\n } else if (relation.direction === \"inverse\" && relation.joinPath && relation.joinPath.length > 0) {\n const serializedValue = serializePropertyToServer(effectiveValue, property);\n if (relation.cardinality === \"one\") {\n // One-to-one inverse joinPath: route through joinPathRelationUpdates.\n // The write ordering in EntityPersistService ensures these are processed\n // BEFORE the main UPDATE, so parentSourceCol reads the pre-update FK value.\n // This prevents stale values from corrupting related entities when an\n // intermediate FK (e.g. author_id) changes in the same save.\n joinPathRelationUpdates.push({\n relationKey: key,\n relation,\n newTargetId: serializedValue as string | number | null\n });\n } else {\n // Many inverse joinPath: capture as inverse relation update\n const pks = getPrimaryKeys(collection, registry!);\n inverseRelationUpdates.push({\n relationKey: key,\n relation,\n newValue: serializedValue,\n currentEntityId: (entity.id as string | number | undefined) || buildCompositeId(entity, pks)\n });\n }\n // Don't add the original relation property to the result\n continue;\n } else if (relation.cardinality === \"one\" && relation.direction === \"owning\" && relation.joinPath && relation.joinPath.length > 0) {\n // Owning one-to-one via joinPath: capture as a write intent\n const serializedValue = serializePropertyToServer(effectiveValue, property);\n joinPathRelationUpdates.push({\n relationKey: key,\n relation,\n newTargetId: serializedValue as string | number | null\n });\n // Don't include this property directly in payload\n continue;\n }\n }\n }\n\n result[key] = serializePropertyToServer(effectiveValue, property);\n }\n\n return {\n scalarData: result,\n inverseRelationUpdates,\n joinPathRelationUpdates\n };\n}\n\n/**\n * Serialize a single property value for database storage\n */\nexport function serializePropertyToServer(value: unknown, property: Property): unknown {\n if (value === null || value === undefined) {\n return value;\n }\n\n const propertyType = property.type;\n\n switch (propertyType) {\n case \"relation\":\n if (Array.isArray(value)) {\n return value.map(v => serializePropertyToServer(v, property));\n } else if (typeof value === \"object\" && value !== null && \"id\" in value) {\n return (value as Record<string, unknown>).id;\n }\n if (value === \"\") return null;\n return value;\n\n case \"array\":\n if (Array.isArray(value)) {\n if (property.of) {\n return value.map(item => serializePropertyToServer(item, property.of as Property));\n } else if (property.oneOf) {\n const typeField = property.oneOf.typeField ?? DEFAULT_ONE_OF_TYPE;\n const valueField = property.oneOf.valueField ?? DEFAULT_ONE_OF_VALUE;\n return value.map((e) => {\n if (e === null) return null;\n if (typeof e !== \"object\") return e;\n const rec = e as Record<string, unknown>;\n const type = rec[typeField] as string;\n const childProperty = property.oneOf?.properties[type];\n if (!type || !childProperty) return e;\n return {\n [typeField]: type,\n [valueField]: serializePropertyToServer(rec[valueField], childProperty)\n };\n });\n }\n }\n return value;\n\n case \"map\":\n if (typeof value === \"object\" && property.properties) {\n const result: Record<string, unknown> = {};\n for (const [subKey, subValue] of Object.entries(value)) {\n const subProperty = (property.properties as Properties)[subKey];\n if (subProperty) {\n result[subKey] = serializePropertyToServer(subValue, subProperty);\n } else {\n result[subKey] = subValue;\n }\n }\n return result;\n }\n return value;\n case \"vector\": {\n if (value instanceof Vector) {\n return value.value;\n }\n if (value && typeof value === \"object\" && \"value\" in value && Array.isArray((value as { value: unknown }).value)) {\n return (value as { value: unknown[] }).value.map(Number);\n }\n if (Array.isArray(value)) {\n return value.map(Number);\n }\n return value;\n }\n\n case \"binary\": {\n const decoded = tryDecodeBase64DataUrl(value);\n if (decoded) return decoded;\n if (Buffer.isBuffer(value)) return value;\n return value;\n }\n\n case \"string\":\n default: {\n const decoded = tryDecodeBase64DataUrl(value);\n if (decoded) return decoded;\n return value;\n }\n }\n}\n\n/**\n * Transform IDs back to relation objects for frontend\n */\nexport async function parseDataFromServer<M extends Record<string, unknown>>(\n data: M,\n collection: EntityCollection,\n db?: NodePgDatabase<Record<string, unknown>>,\n registry?: PostgresCollectionRegistry\n): Promise<M> {\n const properties = collection.properties;\n if (!data || !properties) return data;\n\n // Get the normalized relations once\n const resolvedRelations = resolveCollectionRelations(collection);\n\n // Shared scalar + relation value normalization\n const result = normalizeScalarValues(data, properties, collection, resolvedRelations, { skipRelations: false });\n\n // Add relation properties that should be populated from FK values or inverse queries\n for (const [propKey, property] of Object.entries(properties)) {\n if (property.type === \"relation\" && !(propKey in result)) {\n // Find the normalized relation for this property\n const relation = findRelation(resolvedRelations, propKey);\n if (relation) {\n if (relation.direction === \"owning\" && relation.localKey && relation.localKey in data) {\n // Owning relation: FK is in current table\n const fkValue = data[relation.localKey as keyof M];\n if (fkValue !== null && fkValue !== undefined) {\n try {\n const targetCollection = relation.target();\n result[propKey] = createRelationRef(fkValue.toString(), targetCollection.slug);\n } catch (e) {\n logger.warn(`Could not resolve target collection for relation property: ${propKey}`, { error: e });\n }\n }\n } else if (relation.direction === \"inverse\" && relation.foreignKeyOnTarget && db && registry) {\n // Inverse relation: FK is in target table, need to query for it\n try {\n const targetCollection = relation.target();\n const targetTable = registry.getTable(getTableName(targetCollection));\n const pks = getPrimaryKeys(collection, registry!);\n const currentEntityId = buildCompositeId(data, pks);\n\n if (targetTable && currentEntityId) {\n const foreignKeyColumn = targetTable[relation.foreignKeyOnTarget as keyof typeof targetTable] as AnyPgColumn;\n if (foreignKeyColumn) {\n // Query the target table to find entity that references this entity\n const relatedEntities = await db\n .select()\n .from(targetTable)\n .where(eq(foreignKeyColumn, currentEntityId))\n .limit(relation.cardinality === \"one\" ? 1 : 100); // Limit for one-to-one vs one-to-many\n\n if (relatedEntities.length > 0) {\n if (relation.cardinality === \"one\") {\n // One-to-one: return single relation object\n const targetPks = getPrimaryKeys(targetCollection, registry!);\n const relatedEntity = relatedEntities[0] as Record<string, unknown>;\n result[propKey] = createRelationRef(buildCompositeId(relatedEntity, targetPks), targetCollection.slug);\n } else {\n // One-to-many: return array of relation objects\n const targetPks = getPrimaryKeys(targetCollection, registry!);\n result[propKey] = relatedEntities.map((entity: Record<string, unknown>) =>\n createRelationRef(buildCompositeId(entity, targetPks), targetCollection.slug)\n );\n }\n }\n }\n }\n } catch (e) {\n logger.warn(`Could not resolve inverse relation property: ${propKey}`, { error: e });\n }\n } else if (relation.direction === \"inverse\" && relation.joinPath && db && registry) {\n // Join path relation: Multi-hop relation using joins\n try {\n const targetCollection = relation.target();\n const pks = getPrimaryKeys(collection, registry!);\n const currentEntityId = buildCompositeId(data, pks);\n\n if (currentEntityId) {\n // Build the join query following the join path\n const sourceTable = registry.getTable(getTableName(collection));\n if (!sourceTable) {\n logger.warn(`Source table not found for collection: ${collection.slug}`);\n continue;\n }\n\n let query = db.select().from(sourceTable);\n let currentTable = sourceTable;\n\n // Apply each join in the path\n for (const join of relation.joinPath) {\n const joinTable = registry.getTable(join.table);\n if (!joinTable) {\n logger.warn(`Join table not found: ${join.table}`);\n break;\n }\n\n // Parse the join condition - handle both string and array formats\n const fromColumn = Array.isArray(join.on.from) ? join.on.from[0] : join.on.from;\n const toColumn = Array.isArray(join.on.to) ? join.on.to[0] : join.on.to;\n\n const fromParts = fromColumn.split(\".\");\n const toParts = toColumn.split(\".\");\n\n const fromColName = fromParts[fromParts.length - 1];\n const toColName = toParts[toParts.length - 1];\n\n const fromCol = currentTable[fromColName as keyof typeof currentTable] as AnyPgColumn;\n const toCol = joinTable[toColName as keyof typeof joinTable] as AnyPgColumn;\n\n if (!fromCol || !toCol) {\n logger.warn(`Join columns not found: ${fromColumn} -> ${toColumn}`);\n break;\n }\n\n query = query.innerJoin(joinTable, eq(fromCol, toCol)) as unknown as typeof query;\n currentTable = joinTable;\n }\n\n // Add where condition for the current entity\n if (pks.length === 1) {\n const sourceIdField = sourceTable[pks[0].fieldName as keyof typeof sourceTable] as AnyPgColumn;\n query = query.where(eq(sourceIdField, currentEntityId)) as typeof query;\n } else {\n // For composite keys, we would need to map the split parts. For now log a warning.\n logger.warn(`Join path resolution for composite primary keys is not yet fully supported: ${collection.slug}`);\n }\n\n // Build additional conditions array\n const additionalFilters: SQL[] = [];\n\n // Combine parent condition with additional filters using AND\n let combinedWhere: SQL | undefined;\n\n if (pks.length === 1) {\n const sourceIdField = sourceTable[pks[0].fieldName as keyof typeof sourceTable] as AnyPgColumn;\n combinedWhere = DrizzleConditionBuilder.combineConditionsWithAnd([\n eq(sourceIdField, currentEntityId),\n ...additionalFilters\n ].filter(Boolean) as SQL[]);\n }\n\n // Execute the query\n const joinResults = await query.where(combinedWhere).limit(relation.cardinality === \"one\" ? 1 : 100);\n\n if (joinResults.length > 0) {\n const targetPks = getPrimaryKeys(targetCollection, registry!);\n const targetTableName = relation.joinPath[relation.joinPath.length - 1].table;\n\n if (relation.cardinality === \"one\") {\n // One-to-one: return single relation object\n const joinResult = joinResults[0] as Record<string, unknown>;\n const targetEntity = (joinResult[targetTableName] || joinResult) as Record<string, unknown>;\n result[propKey] = createRelationRef(buildCompositeId(targetEntity, targetPks), targetCollection.slug);\n } else {\n // One-to-many: return array of relation objects\n result[propKey] = joinResults.map((joinResult: Record<string, unknown>) => {\n const targetEntity = (joinResult[targetTableName] || joinResult) as Record<string, unknown>;\n return createRelationRef(buildCompositeId(targetEntity, targetPks), targetCollection.slug);\n });\n }\n }\n }\n } catch (e) {\n logger.warn(`Could not resolve join path relation property: ${propKey}`, { error: e });\n }\n }\n }\n }\n }\n\n return result as M;\n}\n\n/**\n * Try to decode a `data:application/octet-stream;base64,...` data URL string\n * into a Buffer. Returns null if the value is not a matching data URL.\n */\nfunction tryDecodeBase64DataUrl(value: unknown): Buffer | null {\n if (typeof value !== \"string\") return null;\n if (!value.startsWith(\"data:application/octet-stream;base64,\")) return null;\n const base64Data = value.split(\",\")[1];\n return base64Data ? Buffer.from(base64Data, \"base64\") : null;\n}\n\n/**\n * Try to resolve an unknown value into a Buffer.\n * Handles native Buffers and `{ type: \"Buffer\", data: number[] }` objects (from JSON deserialization).\n * Returns null if the value is not a buffer.\n */\nfunction tryResolveBuffer(value: unknown): Buffer | null {\n if (Buffer.isBuffer(value)) return value;\n if (typeof value === \"object\" && value !== null) {\n const rawVal = value as Record<string, unknown>;\n if (rawVal.type === \"Buffer\" && Array.isArray(rawVal.data)) {\n return Buffer.from(rawVal.data as number[]);\n }\n }\n return null;\n}\n\n/**\n * Convert a Buffer to a UTF-8 string if all bytes are printable ASCII,\n * otherwise return a base64 data URL.\n */\nfunction bufferToStringOrBase64(buf: Buffer): string {\n for (let i = 0; i < buf.length; i++) {\n const b = buf[i];\n // Allow standard printable ASCII + common whitespace (\\r, \\n, \\t)\n if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {\n return `data:application/octet-stream;base64,${buf.toString(\"base64\")}`;\n }\n }\n return buf.toString(\"utf8\");\n}\n\nexport function parsePropertyFromServer(value: unknown, property: Property, collection: EntityCollection, propertyKey?: string): unknown {\n if (value === null || value === undefined) return value;\n\n switch (property.type) {\n case \"binary\": {\n const buf = tryResolveBuffer(value);\n if (buf) {\n return `data:application/octet-stream;base64,${buf.toString(\"base64\")}`;\n }\n return value;\n }\n\n case \"string\": {\n if (typeof value === \"string\") return value;\n\n // Handle Buffer objects (e.g. from PostgreSQL bytea columns)\n const buf = tryResolveBuffer(value);\n if (buf) {\n return bufferToStringOrBase64(buf);\n }\n\n if (typeof value === \"object\" && value !== null) {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n }\n\n case \"relation\":\n // Transform ID back to relation object with type information\n if (typeof value === \"string\" || typeof value === \"number\") {\n let relationDef: Relation | undefined = (property as RelationProperty).relation;\n if (!relationDef && propertyKey) {\n const resolvedRelations = resolveCollectionRelations(collection);\n relationDef = findRelation(resolvedRelations, propertyKey);\n }\n if (!relationDef) {\n relationDef = (collection as CollectionWithRelations).relations?.find((rel: Relation) => rel.relationName === (property as RelationProperty).relationName);\n }\n\n if (!relationDef) {\n logger.warn(`Relation not defined in property for key: ${propertyKey || \"unknown\"}`);\n return value;\n }\n\n try {\n const targetCollection = relationDef.target();\n return createRelationRef(value.toString(), targetCollection.slug);\n } catch (e) {\n logger.warn(`Could not resolve target collection for relation property: ${propertyKey || \"unknown\"}`, { error: e });\n return value;\n }\n }\n return value;\n\n case \"array\":\n if (Array.isArray(value)) {\n if (property.of) {\n return value.map(item => parsePropertyFromServer(item, property.of as Property, collection));\n } else if (property.oneOf) {\n const typeField = property.oneOf.typeField ?? DEFAULT_ONE_OF_TYPE;\n const valueField = property.oneOf.valueField ?? DEFAULT_ONE_OF_VALUE;\n return value.map((e) => {\n if (e === null) return null;\n if (typeof e !== \"object\") return e;\n const rec = e as Record<string, unknown>;\n const type = rec[typeField] as string;\n const childProperty = property.oneOf?.properties[type];\n if (!type || !childProperty) return e;\n return {\n [typeField]: type,\n [valueField]: parsePropertyFromServer(rec[valueField], childProperty, collection)\n };\n });\n }\n }\n return value;\n\n case \"map\":\n if (typeof value === \"object\" && property.properties) {\n const result: Record<string, unknown> = {};\n for (const [subKey, subValue] of Object.entries(value)) {\n const subProperty = (property.properties as Properties)[subKey];\n if (subProperty) {\n result[subKey] = parsePropertyFromServer(subValue, subProperty, collection);\n } else {\n result[subKey] = subValue;\n }\n }\n return result;\n }\n return value;\n\n case \"number\":\n if (typeof value === \"string\") {\n const parsed = parseFloat(value);\n return isNaN(parsed) ? null : parsed;\n }\n return value;\n\n case \"vector\": {\n let nums: number[] = [];\n if (typeof value === \"string\") {\n nums = value.slice(1, -1).split(\",\").map(Number);\n } else if (Array.isArray(value)) {\n nums = value.map(Number);\n } else if (value instanceof Vector) {\n nums = value.value;\n } else if (typeof value === \"object\" && value !== null && \"value\" in value) {\n const valObj = value as { value: unknown };\n if (Array.isArray(valObj.value)) {\n nums = valObj.value.map(Number);\n }\n }\n return {\n __type: \"Vector\",\n value: nums\n };\n }\n\n case \"date\": {\n let date: Date | undefined;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === \"string\" || typeof value === \"number\") {\n const parsedDate = new Date(value);\n if (!isNaN(parsedDate.getTime())) {\n date = parsedDate;\n }\n }\n if (date) {\n return {\n __type: \"date\",\n value: date.toISOString()\n };\n }\n return null;\n }\n\n default: {\n // Fallback for buffers in case they are mapped to something other than string\n const buf = tryResolveBuffer(value);\n if (buf) {\n return bufferToStringOrBase64(buf);\n }\n return value;\n }\n }\n}\n\n/**\n * Shared internal helper: normalizes scalar column values from a DB row\n * into frontend format. Handles FK-column preservation, type coercion\n * (dates, numbers, NaN), and property filtering.\n *\n * @param skipRelations When `true`, relation-typed properties are omitted\n * from the result (used by `normalizeDbValues` where\n * Drizzle's relational API already hydrates them).\n */\nfunction normalizeScalarValues<M extends Record<string, unknown>>(\n data: M,\n properties: Properties,\n collection: EntityCollection,\n resolvedRelations: Record<string, Relation>,\n options: { skipRelations: boolean }\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n // Identify FK columns used only for relations and not exposed as properties\n const internalFKColumns = new Set<string>();\n Object.values(resolvedRelations).forEach(relation => {\n if (relation.localKey && !properties[relation.localKey]) {\n internalFKColumns.add(relation.localKey);\n }\n });\n\n for (const [key, value] of Object.entries(data)) {\n // Keep internal FK columns as primitives\n if (internalFKColumns.has(key)) {\n result[key] = value === null ? null : (typeof value === \"number\" ? value : String(value));\n continue;\n }\n\n const property = properties[key as keyof M] as Property;\n if (!property) continue; // Skip DB columns not defined in properties\n\n if (options.skipRelations && property.type === \"relation\") continue;\n\n result[key] = parsePropertyFromServer(value, property, collection, key);\n }\n\n return result;\n}\n\n/**\n * Lightweight value normalization for db.query results.\n * Only handles type coercion (dates, numbers, NaN) and property filtering.\n * Does NOT query the database for relations — those are already resolved\n * by Drizzle's relational query API.\n *\n * Use this instead of `parseDataFromServer` when processing results from\n * `db.query.findFirst/findMany` which return pre-hydrated relation data.\n */\nexport function normalizeDbValues<M extends Record<string, unknown>>(\n data: M,\n collection: EntityCollection\n): M {\n const properties = collection.properties;\n if (!data || !properties) return data;\n\n const resolvedRelations = resolveCollectionRelations(collection);\n return normalizeScalarValues(data, properties, collection, resolvedRelations, { skipRelations: true }) as M;\n}\n","import { and, eq, inArray, sql, SQL } from \"drizzle-orm\";\nimport { AnyPgColumn, PgTable } from \"drizzle-orm/pg-core\";\nimport { DrizzleClient } from \"../interfaces\";\nimport { Entity, EntityCollection, FilterValues, Relation } from \"@rebasepro/types\";\nimport { getTableName, resolveCollectionRelations, findRelation } from \"@rebasepro/common\";\nimport { DrizzleConditionBuilder } from \"../utils/drizzle-conditions\";\nimport {\n getCollectionByPath,\n getTableForCollection,\n getPrimaryKeys,\n parseIdValues,\n buildCompositeId\n} from \"./entity-helpers\";\nimport { parseDataFromServer } from \"../data-transformer\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/**\n * Typed wrapper for Drizzle dynamic query innerJoin.\n * Drizzle's `$dynamic()` queries lose the `innerJoin` method from\n * their static type, but it exists at runtime. This helper bridges\n * the gap with a single confined cast.\n */\nfunction applyDynamicJoin<T>(query: T, joinTable: PgTable, condition: SQL): T {\n return (query as unknown as { innerJoin(t: PgTable, c: SQL): T }).innerJoin(joinTable, condition) as T;\n}\n\n/**\n * Typed wrapper for DrizzleConditionBuilder.buildRelationQuery on dynamic queries.\n * The method returns a widened generic that doesn't reassign cleanly;\n * this helper confines the cast.\n */\nfunction applyDynamicRelationQuery<T>(\n query: T,\n ...args: Parameters<typeof DrizzleConditionBuilder.buildRelationQuery>\n): T {\n return DrizzleConditionBuilder.buildRelationQuery(...args) as unknown as T;\n}\n\n/**\n * Service for handling all relation-related operations.\n * Handles fetching, updating, and managing entity relations.\n */\nexport class RelationService {\n constructor(private db: DrizzleClient, private registry: PostgresCollectionRegistry) { }\n\n /**\n * Fetch entities related to a parent entity through a specific relation\n */\n async fetchRelatedEntities<M extends Record<string, unknown>>(\n parentCollectionPath: string,\n parentEntityId: string | number,\n relationKey: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<Entity<M>[]> {\n const parentCollection = getCollectionByPath(parentCollectionPath, this.registry);\n const resolvedRelations = resolveCollectionRelations(parentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n\n if (!relation) {\n const available = Object.keys(resolvedRelations).join(\", \") || \"(none)\";\n throw new Error(`Relation '${relationKey}' not found in collection '${parentCollectionPath}'. Available relations: [${available}]`);\n }\n\n return this.fetchEntitiesUsingJoins<M>(parentCollection, parentEntityId, relation, options);\n }\n\n /**\n * Fetch entities using join paths for complex relations\n */\n async fetchEntitiesUsingJoins<M extends Record<string, unknown>>(\n parentCollection: EntityCollection,\n parentEntityId: string | number,\n relation: Relation,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<Entity<M>[]> {\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const idInfo = getPrimaryKeys(targetCollection, this.registry);\n const idField = targetTable[idInfo[0].fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n const parentPks = getPrimaryKeys(parentCollection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(parentEntityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n const parentTable = this.registry.getTable(getTableName(parentCollection));\n if (!parentTable) throw new Error(\"Parent table not found\");\n const parentIdCol = parentTable[parentIdInfo.fieldName as keyof typeof parentTable] as AnyPgColumn;\n\n // Handle join path relations\n if (relation.joinPath && relation.joinPath.length > 0) {\n let query = this.db.select().from(parentTable).$dynamic();\n let currentTable = parentTable;\n\n // Apply each join in the path\n for (const join of relation.joinPath) {\n const joinTable = this.registry.getTable(join.table);\n if (!joinTable) {\n throw new Error(`Join table not found: ${join.table}`);\n }\n\n const fromColumn = Array.isArray(join.on.from) ? join.on.from[0] : join.on.from;\n const toColumn = Array.isArray(join.on.to) ? join.on.to[0] : join.on.to;\n\n const fromParts = fromColumn.split(\".\");\n const toParts = toColumn.split(\".\");\n\n const fromColName = fromParts[fromParts.length - 1];\n const toColName = toParts[toParts.length - 1];\n\n const fromCol = currentTable[fromColName as keyof typeof currentTable] as AnyPgColumn;\n const toCol = joinTable[toColName as keyof typeof joinTable] as AnyPgColumn;\n\n if (!fromCol || !toCol) {\n throw new Error(`Join columns not found: ${fromColumn} -> ${toColumn}`);\n }\n\n query = applyDynamicJoin(query, joinTable, eq(fromCol, toCol));\n currentTable = joinTable;\n }\n\n // Add where condition for the parent entity\n const parentIdField = parentTable[getPrimaryKeys(parentCollection, this.registry)[0].fieldName as keyof typeof parentTable] as AnyPgColumn;\n query = query.where(eq(parentIdField, parsedParentId));\n\n if (options.limit) {\n query = query.limit(options.limit);\n }\n\n const results = await query;\n const targetTableName = relation.joinPath[relation.joinPath.length - 1].table;\n\n // Process results\n const entities: Entity<M>[] = [];\n for (const row of results as Array<Record<string, unknown>>) {\n const targetEntity = (row[targetTableName] as Record<string, unknown>) || row;\n const entityId = targetEntity[idInfo[0].fieldName as string];\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection, this.db, this.registry);\n\n entities.push({\n id: entityId?.toString() || \"\",\n path: targetCollection.slug,\n values: parsedValues as M\n });\n }\n\n return entities;\n }\n\n // Handle other relation types\n let query = this.db.select().from(targetTable).$dynamic();\n\n // Build additional filter conditions\n const additionalFilters: SQL[] = [];\n\n // Handle search conditions if searchString is provided\n if (options.searchString) {\n const searchConditions = DrizzleConditionBuilder.buildSearchConditions(\n options.searchString,\n targetCollection.properties,\n targetTable\n );\n\n if (searchConditions.length === 0) {\n // No searchable fields found, return empty results\n return [];\n }\n\n const searchCombined = DrizzleConditionBuilder.combineConditionsWithOr(searchConditions);\n if (searchCombined) {\n additionalFilters.push(searchCombined);\n }\n }\n\n // Use unified relation query builder\n query = applyDynamicRelationQuery(\n query,\n query,\n relation,\n parsedParentId,\n targetTable,\n parentTable,\n parentIdCol,\n idField,\n this.registry,\n additionalFilters\n );\n\n if (options.limit) {\n query = query.limit(options.limit);\n }\n\n const results = await query;\n\n // Process results - ensure results is iterable\n if (!results || !Array.isArray(results)) {\n return [];\n }\n\n const entities: Entity<M>[] = [];\n for (const row of results) {\n const targetEntity = row[getTableName(targetCollection)] || row;\n const entityId = targetEntity[idInfo[0].fieldName];\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection, this.db, this.registry);\n\n entities.push({\n id: entityId?.toString() || \"\",\n path: targetCollection.slug,\n values: parsedValues as M\n });\n }\n\n return entities;\n }\n\n /**\n * Count related entities for a parent entity\n */\n async countRelatedEntities<M extends Record<string, unknown>>(\n parentCollectionPath: string,\n parentEntityId: string | number,\n relationKey: string,\n options: { filter?: FilterValues<Extract<keyof M, string>>; databaseId?: string } = {}\n ): Promise<number> {\n const parentCollection = getCollectionByPath(parentCollectionPath, this.registry);\n const resolvedRelations = resolveCollectionRelations(parentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n if (!relation) {\n const available = Object.keys(resolvedRelations).join(\", \") || \"(none)\";\n throw new Error(`Relation '${relationKey}' not found in collection '${parentCollectionPath}'. Available relations: [${available}]`);\n }\n\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetIdField = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n const parentPks = getPrimaryKeys(parentCollection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(parentEntityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n const parentTable = this.registry.getTable(getTableName(parentCollection));\n if (!parentTable) throw new Error(\"Parent table not found\");\n const parentIdCol = parentTable[parentIdInfo.fieldName as keyof typeof parentTable] as AnyPgColumn;\n\n // Start count with distinct to avoid duplicates from junction tables\n let query = this.db.select({ count: sql<number>`count(distinct ${targetIdField})` }).from(targetTable).$dynamic();\n\n // Build additional filter conditions\n const additionalFilters: SQL[] = [];\n\n // Use unified count query builder from DrizzleConditionBuilder\n query = DrizzleConditionBuilder.buildRelationCountQuery(\n query,\n relation,\n parsedParentId,\n targetTable,\n parentTable,\n parentIdCol,\n targetIdField,\n this.registry,\n additionalFilters\n );\n\n const result = await query;\n return Number(result[0]?.count || 0);\n }\n\n /**\n * Batch fetch related entities for multiple parent entities to avoid N+1 queries\n */\n async batchFetchRelatedEntities(\n parentCollectionPath: string,\n parentEntityIds: (string | number)[],\n _relationKey: string,\n relation: Relation\n ): Promise<Map<string, Entity<Record<string, unknown>>>> {\n if (parentEntityIds.length === 0) return new Map();\n\n const parentCollection = getCollectionByPath(parentCollectionPath, this.registry);\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetIdField = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n const parentPks = getPrimaryKeys(parentCollection, this.registry);\n const parentIdInfo = parentPks[0];\n const parentTable = this.registry.getTable(getTableName(parentCollection));\n if (!parentTable) throw new Error(\"Parent table not found\");\n const parentIdCol = parentTable[parentIdInfo.fieldName as keyof typeof parentTable] as AnyPgColumn;\n\n // Parse all parent IDs once\n const parsedParentIds = parentEntityIds.map(id => parseIdValues(id, parentPks)[parentIdInfo.fieldName]);\n\n // Handle join path relations with batching\n if (relation.joinPath && relation.joinPath.length > 0) {\n let query = this.db.select().from(parentTable).$dynamic();\n let currentTable = parentTable;\n\n // Apply each join in the path\n for (const join of relation.joinPath) {\n const joinTable = this.registry.getTable(join.table);\n if (!joinTable) {\n throw new Error(`Join table not found: ${join.table}`);\n }\n\n const fromColumn = Array.isArray(join.on.from) ? join.on.from[0] : join.on.from;\n const toColumn = Array.isArray(join.on.to) ? join.on.to[0] : join.on.to;\n\n const fromParts = fromColumn.split(\".\");\n const toParts = toColumn.split(\".\");\n\n const fromColName = fromParts[fromParts.length - 1];\n const toColName = toParts[toParts.length - 1];\n\n const fromCol = currentTable[fromColName as keyof typeof currentTable] as AnyPgColumn;\n const toCol = joinTable[toColName as keyof typeof joinTable] as AnyPgColumn;\n\n if (!fromCol || !toCol) {\n throw new Error(`Join columns not found: ${fromColumn} -> ${toColumn}`);\n }\n\n query = applyDynamicJoin(query, joinTable, eq(fromCol, toCol));\n currentTable = joinTable;\n }\n\n // Add where condition for ALL parent entities at once\n const parentIdField = parentTable[getPrimaryKeys(parentCollection, this.registry)[0].fieldName as keyof typeof parentTable] as AnyPgColumn;\n query = query.where(inArray(parentIdField, parsedParentIds));\n\n const results = await query;\n const targetTableName = relation.joinPath[relation.joinPath.length - 1].table;\n const resultMap = new Map<string, Entity<Record<string, unknown>>>();\n\n // Group results by parent ID\n for (const row of results as Array<Record<string, unknown>>) {\n const parentEntity = (row[getTableName(parentCollection)] || row) as Record<string, unknown>;\n const targetEntity = (row[targetTableName] || row) as Record<string, unknown>;\n const parentId = parentEntity[parentIdInfo.fieldName] as string | number;\n\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection);\n\n resultMap.set(String(parentId), {\n id: String(targetEntity[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n }\n\n return resultMap;\n }\n\n // Handle owning relations with proper FK-based batching.\n // For owning relations, parent entities hold the FK (e.g. posts.author_id).\n // We need to:\n // 1. Fetch FK values from the parent table in a single query\n // 2. Query the target table with unique FK values\n // 3. Map results back to parent entities via their FK values\n if (relation.direction === \"owning\" && relation.localKey) {\n const localKeyCol = parentTable[relation.localKey as keyof typeof parentTable] as AnyPgColumn;\n if (!localKeyCol) {\n throw new Error(`Local key column '${relation.localKey}' not found in parent table`);\n }\n\n // Step 1: Fetch all FK values from parent table in ONE query\n const fkRows = await this.db\n .select({\n parentId: parentIdCol,\n fkValue: localKeyCol\n })\n .from(parentTable)\n .where(inArray(parentIdCol, parsedParentIds));\n\n // Build parentId → fkValue mapping and collect unique FK values\n const parentToFk = new Map<string, string | number>();\n const uniqueFkValues: (string | number)[] = [];\n const seenFks = new Set<string>();\n\n for (const row of fkRows as Array<{ parentId: string | number; fkValue: string | number | null }>) {\n if (row.fkValue == null) continue;\n parentToFk.set(String(row.parentId), row.fkValue);\n const fkStr = String(row.fkValue);\n if (!seenFks.has(fkStr)) {\n seenFks.add(fkStr);\n uniqueFkValues.push(row.fkValue);\n }\n }\n\n if (uniqueFkValues.length === 0) return new Map();\n\n // Step 2: Fetch all target entities in ONE query\n const targetResults = await this.db\n .select()\n .from(targetTable)\n .where(inArray(targetIdField, uniqueFkValues));\n\n // Index target entities by their ID\n const targetById = new Map<string, Record<string, unknown>>();\n for (const row of targetResults as Array<Record<string, unknown>>) {\n const tid = String(row[targetIdInfo.fieldName]);\n targetById.set(tid, row);\n }\n\n // Step 3: Map back to parent entities\n const resultMap = new Map<string, Entity<Record<string, unknown>>>();\n for (const [parentIdStr, fkValue] of parentToFk) {\n const targetEntity = targetById.get(String(fkValue));\n if (targetEntity) {\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection);\n resultMap.set(parentIdStr, {\n id: String(targetEntity[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n }\n }\n\n return resultMap;\n }\n\n // Handle inverse relation types with batching\n let query = this.db.select().from(targetTable).$dynamic();\n\n // Build the relation query with ALL parent IDs\n query = applyDynamicRelationQuery(\n query,\n query,\n relation,\n parsedParentIds, // Pass array instead of single ID\n targetTable,\n parentTable,\n parentIdCol,\n targetIdField,\n this.registry,\n []\n );\n\n const results = await query;\n const resultMap = new Map<string, Entity<Record<string, unknown>>>();\n\n // Build a Set<string> for O(1) parent-ID lookups that is immune to\n // number-vs-string type mismatches (Drizzle may return either depending\n // on the column type and driver).\n const parentIdSet = new Set(parsedParentIds.map(String));\n\n // Map results back to parent entities\n for (const row of results as Array<Record<string, unknown>>) {\n const targetEntity = (row[getTableName(targetCollection)] || row) as Record<string, unknown>;\n\n // Determine the parent ID this result belongs to based on the relation type\n let parentId: string | number | undefined;\n\n if (relation.direction === \"inverse\" && relation.foreignKeyOnTarget) {\n parentId = targetEntity[relation.foreignKeyOnTarget] as string | number | undefined;\n } else if (relation.direction === \"inverse\" && relation.cardinality === \"one\" && relation.inverseRelationName) {\n const inferredForeignKeyName = `${relation.inverseRelationName}_id`;\n parentId = targetEntity[inferredForeignKeyName] as string | number | undefined;\n }\n\n if (parentId !== undefined && parentIdSet.has(String(parentId))) {\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection);\n resultMap.set(String(parentId), {\n id: String(targetEntity[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n }\n }\n\n return resultMap;\n }\n\n /**\n * Batch fetch many-cardinality related entities for multiple parent entities.\n * Returns a Map<parentId, Entity[]> instead of Map<parentId, Entity>.\n * Uses a single SQL query with IN clause to avoid N+1.\n */\n async batchFetchRelatedEntitiesMany(\n parentCollectionPath: string,\n parentEntityIds: (string | number)[],\n _relationKey: string,\n relation: Relation\n ): Promise<Map<string, Entity<Record<string, unknown>>[]>> {\n if (parentEntityIds.length === 0) return new Map();\n\n const parentCollection = getCollectionByPath(parentCollectionPath, this.registry);\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetIdField = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n const parentPks = getPrimaryKeys(parentCollection, this.registry);\n const parentIdInfo = parentPks[0];\n const parentTable = this.registry.getTable(getTableName(parentCollection));\n if (!parentTable) throw new Error(\"Parent table not found\");\n const parentIdCol = parentTable[parentIdInfo.fieldName as keyof typeof parentTable] as AnyPgColumn;\n\n const parsedParentIds = parentEntityIds.map(id => parseIdValues(id, parentPks)[parentIdInfo.fieldName]);\n\n // Handle join path relations (many-to-many through junction tables)\n if (relation.joinPath && relation.joinPath.length > 0) {\n let query = this.db.select().from(parentTable).$dynamic();\n let currentTable = parentTable;\n\n for (const join of relation.joinPath) {\n const joinTable = this.registry.getTable(join.table);\n if (!joinTable) throw new Error(`Join table not found: ${join.table}`);\n\n const fromColumn = Array.isArray(join.on.from) ? join.on.from[0] : join.on.from;\n const toColumn = Array.isArray(join.on.to) ? join.on.to[0] : join.on.to;\n const fromColName = fromColumn.split(\".\").pop()!;\n const toColName = toColumn.split(\".\").pop()!;\n\n const fromCol = currentTable[fromColName as keyof typeof currentTable] as AnyPgColumn;\n const toCol = joinTable[toColName as keyof typeof joinTable] as AnyPgColumn;\n if (!fromCol || !toCol) throw new Error(`Join columns not found: ${fromColumn} -> ${toColumn}`);\n\n query = applyDynamicJoin(query, joinTable, eq(fromCol, toCol));\n currentTable = joinTable;\n }\n\n const parentIdField = parentTable[getPrimaryKeys(parentCollection, this.registry)[0].fieldName as keyof typeof parentTable] as AnyPgColumn;\n query = query.where(inArray(parentIdField, parsedParentIds));\n\n const results = await query;\n const targetTableName = relation.joinPath[relation.joinPath.length - 1].table;\n const resultMap = new Map<string, Entity<Record<string, unknown>>[]>();\n\n for (const row of results as Array<Record<string, unknown>>) {\n const parentEntity = (row[getTableName(parentCollection)] || row) as Record<string, unknown>;\n const targetEntity = (row[targetTableName] || row) as Record<string, unknown>;\n const parentId = String(parentEntity[parentIdInfo.fieldName]);\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection);\n\n const arr = resultMap.get(parentId) || [];\n arr.push({\n id: String(targetEntity[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n resultMap.set(parentId, arr);\n }\n\n return resultMap;\n }\n\n // Handle many-to-many owning relations with junction table (relation.through)\n // This is the standard path for posts→tags style relations where\n // sanitizeRelation populated the `through` config.\n if (relation.through && relation.cardinality === \"many\" && relation.direction === \"owning\") {\n const junctionTable = this.registry.getTable(relation.through.table);\n if (!junctionTable) {\n logger.warn(`[batchFetchRelatedEntitiesMany] Junction table '${relation.through.table}' not found`);\n return new Map();\n }\n\n const sourceJunctionCol = junctionTable[relation.through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const targetJunctionCol = junctionTable[relation.through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!sourceJunctionCol || !targetJunctionCol) {\n logger.warn(`[batchFetchRelatedEntitiesMany] Junction columns not found in '${relation.through.table}'`);\n return new Map();\n }\n\n // SELECT target.*, junction.sourceColumn FROM junction\n // INNER JOIN target ON junction.targetColumn = target.id\n // WHERE junction.sourceColumn IN (parentIds)\n const query = this.db\n .select()\n .from(junctionTable)\n .innerJoin(targetTable, eq(targetJunctionCol, targetIdField))\n .where(inArray(sourceJunctionCol, parsedParentIds));\n\n const results = await query;\n const resultMap = new Map<string, Entity<Record<string, unknown>>[]>();\n const targetTableName = getTableName(targetCollection);\n\n for (const row of results as Array<Record<string, unknown>>) {\n // The junction table data is namespaced under its table name\n const junctionData = (row[relation.through.table] || row) as Record<string, unknown>;\n const targetData = (row[targetTableName] || row) as Record<string, unknown>;\n\n const parentId = String(junctionData[relation.through.sourceColumn]);\n const parsedValues = await parseDataFromServer(targetData, targetCollection);\n\n const arr = resultMap.get(parentId) || [];\n arr.push({\n id: String(targetData[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n resultMap.set(parentId, arr);\n }\n\n return resultMap;\n }\n\n // Handle FK-based relations (one-to-many inverse)\n let query = this.db.select().from(targetTable).$dynamic();\n\n query = applyDynamicRelationQuery(\n query,\n query,\n relation,\n parsedParentIds,\n targetTable,\n parentTable,\n parentIdCol,\n targetIdField,\n this.registry,\n []\n );\n\n const results = await query;\n const resultMap = new Map<string, Entity<Record<string, unknown>>[]>();\n\n // Build a Set<string> for O(1) parent-ID lookups that is immune to\n // number-vs-string type mismatches (Drizzle may return either depending\n // on the column type and driver).\n const parentIdSet = new Set(parsedParentIds.map(String));\n\n for (const row of results as Array<Record<string, unknown>>) {\n const targetEntity = (row[getTableName(targetCollection)] || row) as Record<string, unknown>;\n\n let parentId: string | number | undefined;\n\n if (relation.through && relation.direction === \"inverse\") {\n // Inverse many-to-many via junction table: the junction's targetColumn\n // references the parent (since from the inverse perspective, source/target are swapped).\n const junctionData = (row[relation.through.table] || row) as Record<string, unknown>;\n parentId = junctionData[relation.through.targetColumn] as string | number | undefined;\n } else if (relation.direction === \"inverse\" && relation.foreignKeyOnTarget) {\n parentId = targetEntity[relation.foreignKeyOnTarget] as string | number | undefined;\n } else if (relation.direction === \"inverse\" && relation.inverseRelationName) {\n const inferredForeignKeyName = `${relation.inverseRelationName}_id`;\n parentId = targetEntity[inferredForeignKeyName] as string | number | undefined;\n }\n\n if (parentId !== undefined && parentIdSet.has(String(parentId))) {\n const parsedValues = await parseDataFromServer(targetEntity, targetCollection);\n const key = String(parentId);\n const arr = resultMap.get(key) || [];\n arr.push({\n id: String(targetEntity[targetIdInfo.fieldName]),\n path: targetCollection.slug,\n values: parsedValues as Record<string, unknown>\n });\n resultMap.set(key, arr);\n }\n }\n\n return resultMap;\n }\n\n /**\n * Update many-to-many and junction relations\n */\n async updateRelationsUsingJoins<M extends Record<string, unknown>>(\n tx: DrizzleClient,\n collection: EntityCollection,\n entityId: string | number,\n relationValues: Partial<M>\n ) {\n const resolvedRelations = resolveCollectionRelations(collection);\n\n for (const [key, value] of Object.entries(relationValues)) {\n const relation = findRelation(resolvedRelations, key);\n if (!relation || relation.cardinality !== \"many\") continue;\n\n const targetEntityIds = (value && Array.isArray(value)) ? value.map((rel: { id: string | number }) => rel.id) : [];\n const targetCollection = relation.target();\n\n // Use joinPath if available\n if (relation.joinPath && relation.joinPath.length > 0) {\n const parentTableName = getTableName(collection);\n const targetTableName = getTableName(targetCollection);\n\n let junctionTable: PgTable | undefined = undefined;\n let sourceJunctionColumn: AnyPgColumn | null = null;\n let targetJunctionColumn: AnyPgColumn | null = null;\n\n const junctionTableName = relation.joinPath.find(step =>\n step.table !== parentTableName && step.table !== targetTableName\n )?.table;\n\n if (junctionTableName) {\n junctionTable = this.registry.getTable(junctionTableName);\n\n if (junctionTable) {\n for (const joinStep of relation.joinPath) {\n const fromTable = DrizzleConditionBuilder.getTableNamesFromColumns(joinStep.on.from)[0];\n const toTable = DrizzleConditionBuilder.getTableNamesFromColumns(joinStep.on.to)[0];\n\n if (fromTable === parentTableName && toTable === junctionTableName) {\n const columnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(joinStep.on.to);\n sourceJunctionColumn = junctionTable[columnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n } else if (fromTable === junctionTableName && toTable === parentTableName) {\n const columnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(joinStep.on.from);\n sourceJunctionColumn = junctionTable[columnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n }\n\n if (fromTable === junctionTableName && toTable === targetTableName) {\n const columnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(joinStep.on.from);\n targetJunctionColumn = junctionTable[columnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n } else if (fromTable === targetTableName && toTable === junctionTableName) {\n const columnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(joinStep.on.to);\n targetJunctionColumn = junctionTable[columnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n }\n }\n }\n }\n\n if (!junctionTable || !sourceJunctionColumn || !targetJunctionColumn) {\n logger.warn(`Could not determine junction table for relation '${key}' in collection '${collection.slug}'`);\n continue;\n }\n\n const parentPks = getPrimaryKeys(collection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(entityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n // Delete existing relations for this entity\n await tx.delete(junctionTable).where(eq(sourceJunctionColumn, parsedParentId));\n\n if (targetEntityIds.length > 0) {\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const parsedTargetIds = targetEntityIds.map(id => parseIdValues(id, targetPks)[targetIdInfo.fieldName]);\n\n const newLinks = parsedTargetIds.map(targetId => ({\n [sourceJunctionColumn.name]: parsedParentId,\n [targetJunctionColumn.name]: targetId\n }));\n\n if (newLinks.length > 0) {\n await tx.insert(junctionTable).values(newLinks);\n }\n }\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"owning\") {\n // Handle many-to-many relations with junction table using 'through' property\n const junctionTable = this.registry.getTable(relation.through.table);\n if (!junctionTable) {\n logger.warn(`Junction table '${relation.through.table}' not found for relation '${key}' in collection '${collection.slug}'`);\n continue;\n }\n\n const sourceJunctionColumn = junctionTable[relation.through.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const targetJunctionColumn = junctionTable[relation.through.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!sourceJunctionColumn || !targetJunctionColumn) {\n logger.warn(`Junction columns not found for relation '${key}'`);\n continue;\n }\n\n const parentPks = getPrimaryKeys(collection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(entityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n // Delete existing relations for this entity\n await tx.delete(junctionTable).where(eq(sourceJunctionColumn, parsedParentId));\n\n if (targetEntityIds.length > 0) {\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const parsedTargetIds = targetEntityIds.map(id => parseIdValues(id, targetPks)[targetIdInfo.fieldName]);\n\n const newLinks = parsedTargetIds.map(targetId => ({\n [sourceJunctionColumn.name]: parsedParentId,\n [targetJunctionColumn.name]: targetId\n }));\n\n if (newLinks.length > 0) {\n await tx.insert(junctionTable).values(newLinks);\n }\n }\n } else if (relation.through && relation.cardinality === \"many\" && relation.direction === \"inverse\") {\n // Inverse M2M relations should be saved from the owning side.\n // The owning collection manages the junction table rows.\n logger.warn(`[updateRelationsUsingJoins] Inverse M2M relation '${key}' in collection '${collection.slug}' should be saved from the owning side. Skipping.`);\n } else if (relation.cardinality === \"many\" && relation.direction === \"inverse\" && relation.foreignKeyOnTarget) {\n // Handle one-to-many (inverse) by updating target FK to point to parent\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetIdCol = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n const fkCol = targetTable[relation.foreignKeyOnTarget as keyof typeof targetTable] as AnyPgColumn;\n\n if (!fkCol || !targetIdCol) {\n logger.warn(`Invalid inverse-many config for relation '${key}' in collection '${collection.slug}'`);\n continue;\n }\n\n const parentPks = getPrimaryKeys(collection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(entityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n // Clear existing links not in the new set\n if (targetEntityIds.length > 0) {\n const parsedTargetIds = targetEntityIds.map(id => parseIdValues(id, targetPks)[targetIdInfo.fieldName]);\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget]: null })\n .where(and(eq(fkCol, parsedParentId), sql`${targetIdCol} NOT IN (${sql.join(parsedTargetIds)})`));\n\n // Set FK for the provided targets\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget]: parsedParentId })\n .where(inArray(targetIdCol as AnyPgColumn, parsedTargetIds as unknown[]));\n } else {\n // If empty array provided, clear all existing links for this parent\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget]: null })\n .where(eq(fkCol, parsedParentId));\n }\n } else {\n logger.warn(`Many relation '${key}' in collection '${collection.slug}' lacks write configuration and will be skipped during save.`);\n }\n }\n }\n\n /**\n * Update inverse relations (where FK is on the target table)\n */\n async updateInverseRelations(\n tx: DrizzleClient,\n sourceCollection: EntityCollection,\n sourceEntityId: string | number,\n inverseRelationUpdates: Array<{\n relationKey: string;\n relation: Relation;\n newValue: unknown;\n currentEntityId?: string | number;\n }>\n ) {\n for (const update of inverseRelationUpdates) {\n const { relation, newValue } = update;\n\n try {\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const sourcePks = getPrimaryKeys(sourceCollection, this.registry);\n const sourceIdInfo = sourcePks[0];\n\n // Handle inverse relations with joinPath\n if (relation.direction === \"inverse\" && relation.joinPath && relation.joinPath.length > 0) {\n await this.updateInverseJoinPathRelation(\n tx,\n sourceCollection,\n sourceEntityId,\n targetCollection,\n relation,\n newValue\n );\n continue;\n }\n\n // Check if this is a many-to-many inverse relation\n if (relation.cardinality === \"many\" && relation.direction === \"inverse\") {\n const targetCollectionRelations = resolveCollectionRelations(targetCollection);\n let junctionInfo: { table: string; sourceColumn: string; targetColumn: string } | null = null;\n\n for (const [relationKey, targetRelation] of Object.entries(targetCollectionRelations)) {\n if (targetRelation.cardinality === \"many\" &&\n targetRelation.direction === \"owning\" &&\n targetRelation.through &&\n (targetRelation.relationName === relation.inverseRelationName || relationKey === relation.inverseRelationName)) {\n junctionInfo = {\n table: targetRelation.through.table,\n sourceColumn: targetRelation.through.targetColumn,\n targetColumn: targetRelation.through.sourceColumn\n };\n break;\n }\n }\n\n if (junctionInfo) {\n await this.updateManyToManyInverseRelation(\n tx,\n sourceCollection,\n sourceEntityId,\n targetCollection,\n relation,\n newValue,\n junctionInfo\n );\n continue;\n }\n }\n\n // Handle simple inverse relations\n if (!relation.foreignKeyOnTarget) {\n logger.warn(`Inverse relation '${relation.relationName}' is missing foreignKeyOnTarget property. Skipping.`);\n continue;\n }\n\n const foreignKeyColumn = targetTable[relation.foreignKeyOnTarget! as keyof typeof targetTable] as AnyPgColumn;\n if (!foreignKeyColumn) {\n logger.warn(`Foreign key column '${relation.foreignKeyOnTarget}' not found in target table for relation '${relation.relationName}'`);\n continue;\n }\n\n const parsedSourceIdObj = parseIdValues(sourceEntityId, sourcePks);\n const parsedSourceId = parsedSourceIdObj[sourceIdInfo.fieldName];\n\n if (newValue === null || newValue === undefined) {\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget!]: null })\n .where(eq(foreignKeyColumn, parsedSourceId));\n } else {\n const parsedNewTargetIdObj = parseIdValues(newValue as string | number, targetPks);\n const parsedNewTargetId = parsedNewTargetIdObj[targetIdInfo.fieldName];\n const targetIdField = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n // First, clear any existing FK that points to this source entity\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget!]: null })\n .where(eq(foreignKeyColumn, parsedSourceId));\n\n // Then, update the new target entity to point to this source entity\n await tx\n .update(targetTable)\n .set({ [relation.foreignKeyOnTarget!]: parsedSourceId })\n .where(eq(targetIdField, parsedNewTargetId));\n }\n } catch (e) {\n logger.warn(`Failed to update inverse relation '${relation.relationName}'`, { error: e });\n }\n }\n }\n\n /**\n * Handle inverse relations with joinPath\n */\n private async updateInverseJoinPathRelation(\n tx: DrizzleClient,\n sourceCollection: EntityCollection,\n sourceEntityId: string | number,\n targetCollection: EntityCollection,\n relation: Relation,\n newValue: unknown\n ) {\n try {\n if (!relation.joinPath || relation.joinPath.length === 0) {\n logger.warn(`Inverse relation '${relation.relationName}' missing joinPath`);\n return;\n }\n\n const sourceTableName = getTableName(sourceCollection);\n const targetTableName = getTableName(targetCollection);\n\n // Find intermediate tables that are neither source nor target\n const intermediateTables = relation.joinPath\n .map(step => step.table)\n .filter(table => table !== sourceTableName && table !== targetTableName);\n\n // If there's exactly one intermediate table, it's likely a junction table for many-to-many\n if (intermediateTables.length === 1 && relation.cardinality === \"many\") {\n const junctionTableName = intermediateTables[0];\n const junctionTable = this.registry.getTable(junctionTableName);\n\n if (!junctionTable) {\n logger.warn(`Junction table '${junctionTableName}' not found for inverse joinPath relation '${relation.relationName}'`);\n return;\n }\n\n let sourceJunctionColumn: AnyPgColumn | null = null;\n let targetJunctionColumn: AnyPgColumn | null = null;\n\n for (const step of relation.joinPath) {\n if (step.table === junctionTableName) {\n const fromTable = DrizzleConditionBuilder.getTableNamesFromColumns(step.on.from)[0];\n const toColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(step.on.to);\n const fromColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(step.on.from);\n\n if (fromTable === sourceTableName) {\n sourceJunctionColumn = junctionTable[toColumnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n } else if (fromTable === targetTableName) {\n targetJunctionColumn = junctionTable[toColumnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n } else {\n const toTable = DrizzleConditionBuilder.getTableNamesFromColumns(step.on.to)[0];\n if (toTable === sourceTableName) {\n sourceJunctionColumn = junctionTable[fromColumnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n } else if (toTable === targetTableName) {\n targetJunctionColumn = junctionTable[fromColumnNames[0] as keyof typeof junctionTable] as AnyPgColumn;\n }\n }\n }\n }\n\n if (!sourceJunctionColumn || !targetJunctionColumn) {\n logger.warn(`Could not determine junction columns for inverse joinPath relation '${relation.relationName}'`);\n return;\n }\n\n // Perform the junction table update\n const sourcePks = getPrimaryKeys(sourceCollection, this.registry);\n const sourceIdInfo = sourcePks[0];\n const parsedSourceIdObj = parseIdValues(sourceEntityId, sourcePks);\n const parsedSourceId = parsedSourceIdObj[sourceIdInfo.fieldName];\n\n // Clear existing entries for this source entity\n await tx.delete(junctionTable).where(eq(sourceJunctionColumn, parsedSourceId));\n\n // Add new entries if newValue is provided\n if (newValue && Array.isArray(newValue) && newValue.length > 0) {\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetEntityIds = (newValue as Array<{ id: string | number } | string | number>).map((rel) => typeof rel === \"object\" && rel !== null ? rel.id : rel);\n const parsedTargetIds = targetEntityIds.map(id => parseIdValues(id, targetPks)[targetIdInfo.fieldName]);\n\n const newLinks = parsedTargetIds.map(targetId => ({\n [sourceJunctionColumn!.name]: parsedSourceId,\n [targetJunctionColumn!.name]: targetId\n }));\n\n if (newLinks.length > 0) {\n await tx.insert(junctionTable).values(newLinks);\n }\n } else if (newValue && !Array.isArray(newValue)) {\n // Single value for one-to-one\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetId = typeof newValue === \"object\" && newValue !== null ? (newValue as Record<string, unknown>).id as string | number : newValue as string | number;\n const parsedTargetIdObj = parseIdValues(targetId, targetPks);\n const parsedTargetId = parsedTargetIdObj[targetIdInfo.fieldName];\n\n const newLink = {\n [sourceJunctionColumn.name]: parsedSourceId,\n [targetJunctionColumn.name]: parsedTargetId\n };\n\n await tx.insert(junctionTable).values(newLink);\n }\n }\n } catch (error) {\n logger.error(`Failed to update inverse joinPath relation '${relation.relationName}'`, { error: error });\n throw error;\n }\n }\n\n /**\n * Handle many-to-many inverse relation updates using junction tables\n */\n private async updateManyToManyInverseRelation(\n tx: DrizzleClient,\n sourceCollection: EntityCollection,\n sourceEntityId: string | number,\n targetCollection: EntityCollection,\n relation: Relation,\n newValue: unknown,\n junctionInfo: { table: string; sourceColumn: string; targetColumn: string }\n ) {\n try {\n const junctionTable = this.registry.getTable(junctionInfo.table);\n if (!junctionTable) {\n logger.warn(`Junction table '${junctionInfo.table}' not found for many-to-many inverse relation '${relation.relationName}'`);\n return;\n }\n\n const sourceJunctionColumn = junctionTable[junctionInfo.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const targetJunctionColumn = junctionTable[junctionInfo.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!sourceJunctionColumn || !targetJunctionColumn) {\n logger.warn(`Junction columns not found for relation '${relation.relationName}'`);\n return;\n }\n\n const sourcePks = getPrimaryKeys(sourceCollection, this.registry);\n const sourceIdInfo = sourcePks[0];\n const parsedSourceIdObj = parseIdValues(sourceEntityId, sourcePks);\n const parsedSourceId = parsedSourceIdObj[sourceIdInfo.fieldName];\n\n // Clear existing entries for this source entity\n await tx.delete(junctionTable).where(eq(sourceJunctionColumn, parsedSourceId));\n\n // Add new entries if newValue is provided\n if (newValue && Array.isArray(newValue) && newValue.length > 0) {\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetEntityIds = (newValue as Array<{ id: string | number }>).map((rel) => rel.id);\n const parsedTargetIds = targetEntityIds.map(id => parseIdValues(id, targetPks)[targetIdInfo.fieldName]);\n\n const newLinks = parsedTargetIds.map(targetId => ({\n [sourceJunctionColumn.name]: parsedSourceId,\n [targetJunctionColumn.name]: targetId\n }));\n\n if (newLinks.length > 0) {\n await tx.insert(junctionTable).values(newLinks);\n }\n }\n } catch (error) {\n logger.error(`Failed to update many-to-many inverse relation '${relation.relationName}'`, { error: error });\n throw error;\n }\n }\n\n /**\n * Update one-to-one relations that use joinPath\n */\n async updateJoinPathOneToOneRelations(\n tx: DrizzleClient,\n parentCollection: EntityCollection,\n parentEntityId: string | number,\n updates: Array<{\n relationKey: string;\n relation: Relation;\n newTargetId: string | number | null;\n }>\n ) {\n for (const upd of updates) {\n const { relation, newTargetId } = upd;\n const targetCollection = relation.target();\n const targetTable = getTableForCollection(targetCollection, this.registry);\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const targetIdCol = targetTable[targetIdInfo.fieldName as keyof typeof targetTable] as AnyPgColumn;\n\n // Determine mapping of columns\n const { targetFKColName, parentSourceColName } = this.resolveJoinPathWriteMapping(parentCollection, relation);\n const parentTable = getTableForCollection(parentCollection, this.registry);\n const parentPks = getPrimaryKeys(parentCollection, this.registry);\n const parentIdInfo = parentPks[0];\n const parsedParentIdObj = parseIdValues(parentEntityId, parentPks);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n const parentIdCol = parentTable[parentIdInfo.fieldName as keyof typeof parentTable] as AnyPgColumn;\n const parentSourceCol = parentTable[parentSourceColName as keyof typeof parentTable] as AnyPgColumn;\n const targetFKCol = targetTable[targetFKColName as keyof typeof targetTable] as AnyPgColumn;\n\n if (!parentSourceCol) {\n logger.warn(`Parent source column '${parentSourceColName}' not found for joinPath relation '${relation.relationName}'`);\n continue;\n }\n if (!targetFKCol) {\n logger.warn(`Target FK column '${targetFKColName}' not found for joinPath relation '${relation.relationName}'`);\n continue;\n }\n\n // Fetch the parent row to obtain the value for parentSourceCol\n const parentRows = await tx\n .select({ val: parentSourceCol })\n .from(parentTable)\n .where(eq(parentIdCol, parsedParentId))\n .limit(1);\n if (parentRows.length === 0) continue;\n const parentFKValue = parentRows[0].val as string | number | null;\n\n if (newTargetId === null || newTargetId === undefined) {\n // Clear any target rows currently linked to this parent via the FK\n if (parentFKValue !== null && parentFKValue !== undefined) {\n await tx.update(targetTable)\n .set({ [targetFKColName]: null })\n .where(eq(targetFKCol, String(parentFKValue)));\n }\n continue;\n }\n\n // Parse the new target id\n const parsedTargetIdObj = parseIdValues(newTargetId, targetPks);\n const parsedTargetId = parsedTargetIdObj[targetIdInfo.fieldName];\n\n // Ensure one-to-one by clearing existing link from any target rows with this parent FK\n if (parentFKValue !== null && parentFKValue !== undefined) {\n await tx.update(targetTable)\n .set({ [targetFKColName]: null })\n .where(eq(targetFKCol, String(parentFKValue)));\n } else {\n logger.warn(`Cannot set joinPath relation '${relation.relationName}' because parent FK value is null/undefined`);\n continue;\n }\n\n // Now set the FK on the target entity\n await tx.update(targetTable)\n .set({ [targetFKColName]: parentFKValue })\n .where(eq(targetIdCol, parsedTargetId));\n }\n }\n\n /**\n * Resolve joinPath write mapping for one-to-one relations\n */\n resolveJoinPathWriteMapping(\n parentCollection: EntityCollection,\n relation: Relation\n ): { targetFKColName: string; parentSourceColName: string } {\n if (!relation.joinPath || relation.joinPath.length === 0) {\n throw new Error(\"resolveJoinPathWriteMapping requires a joinPath relation\");\n }\n const parentTableName = getTableName(parentCollection);\n const lastStep = relation.joinPath[relation.joinPath.length - 1];\n const targetFKColName = DrizzleConditionBuilder.getColumnNamesFromColumns(lastStep.on.to)[0];\n let currentFrom = lastStep.on.from;\n\n let safety = 0;\n while (safety++ < 10) {\n const currentFromTable = DrizzleConditionBuilder.getTableNamesFromColumns(currentFrom)[0];\n if (currentFromTable === parentTableName) {\n break;\n }\n const prevStep = relation.joinPath.find((s) => {\n const to = Array.isArray(s.on.to) ? s.on.to[0] : s.on.to;\n return to === currentFrom;\n });\n if (!prevStep) {\n throw new Error(`Could not resolve parent source column for joinPath relation '${relation.relationName}'`);\n }\n currentFrom = prevStep.on.from;\n }\n const parentSourceColName = DrizzleConditionBuilder.getColumnNamesFromColumns(currentFrom)[0];\n return { targetFKColName,\nparentSourceColName };\n }\n\n /**\n * Handle junction table creation for many-to-many path-based saves\n */\n async handleJunctionTableCreation(\n tx: DrizzleClient,\n newEntityId: string | number,\n junctionTableInfo: {\n parentCollection: EntityCollection;\n parentId: string | number;\n relation: Relation;\n relationKey: string;\n }\n ) {\n const { parentCollection, parentId, relation, relationKey } = junctionTableInfo;\n const targetCollection = relation.target();\n\n try {\n const junctionTable = this.registry.getTable(relation.through!.table);\n if (!junctionTable) {\n logger.warn(`Junction table '${relation.through!.table}' not found for relation '${relationKey}'`);\n return;\n }\n\n const sourceJunctionColumn = junctionTable[relation.through!.sourceColumn as keyof typeof junctionTable] as AnyPgColumn;\n const targetJunctionColumn = junctionTable[relation.through!.targetColumn as keyof typeof junctionTable] as AnyPgColumn;\n\n if (!sourceJunctionColumn || !targetJunctionColumn) {\n logger.warn(`Junction columns not found for relation '${relationKey}'`);\n return;\n }\n\n // Parse the new entity ID to the correct type\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdInfo = targetPks[0];\n const parsedNewEntityIdObj = parseIdValues(newEntityId, targetPks);\n const parsedNewEntityId = parsedNewEntityIdObj[targetIdInfo.fieldName];\n\n // Create the junction table entry linking parent to the new entity\n const junctionData = {\n [sourceJunctionColumn.name]: parentId,\n [targetJunctionColumn.name]: parsedNewEntityId\n };\n\n await tx.insert(junctionTable).values(junctionData);\n\n logger.info(`Created junction table entry for many-to-many relation '${relationKey}': ${JSON.stringify(junctionData)}`);\n } catch (error) {\n logger.error(`Failed to create junction table entry for relation '${relationKey}'`, { error: error });\n throw error;\n }\n }\n}\n","import { and, asc, count, desc, eq, getTableName, gt, lt, or, SQL, TableRelationalConfig, TablesRelationalConfig } from \"drizzle-orm\";\nimport { AnyPgColumn, PgTable } from \"drizzle-orm/pg-core\";\nimport { Entity, EntityCollection, FilterValues, Relation, LogicalCondition } from \"@rebasepro/types\";\nimport type { VectorSearchParams } from \"@rebasepro/types\";\nimport { resolveCollectionRelations, findRelation, createRelationRef, createRelationRefWithData } from \"@rebasepro/common\";\nimport { DrizzleConditionBuilder } from \"../utils/drizzle-conditions\";\nimport {\n getCollectionByPath,\n getTableForCollection,\n getPrimaryKeys,\n parseIdValues,\n buildCompositeId\n} from \"./entity-helpers\";\nimport { parseDataFromServer, normalizeDbValues } from \"../data-transformer\";\nimport { RelationService } from \"./RelationService\";\nimport { RelationalQueryBuilder } from \"drizzle-orm/pg-core/query-builders/query\";\nimport { DrizzleClient } from \"../interfaces\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/** Type-safe accessor for Drizzle's relational query API via dynamic table name */\ntype DbQueryAccessor = Record<string, RelationalQueryBuilder<any, any>> | undefined;\n\n/**\n * Service for handling all entity read operations.\n * Handles fetching, searching, counting, and filtering entities.\n */\nexport class EntityFetchService {\n private relationService: RelationService;\n\n constructor(private db: DrizzleClient, private registry: PostgresCollectionRegistry) {\n this.relationService = new RelationService(db, registry);\n }\n\n /**\n * Get the relational query builder for a given table name.\n * Safely narrows the DrizzleClient union type to access db.query[tableName].\n */\n private getQueryBuilder(tableName: string): RelationalQueryBuilder<TablesRelationalConfig, TableRelationalConfig> | undefined {\n const query = (this.db as { query?: DbQueryAccessor }).query;\n return query?.[tableName] as RelationalQueryBuilder<TablesRelationalConfig, TableRelationalConfig> | undefined;\n }\n\n /**\n * Build filter conditions from FilterValues\n * Delegates to DrizzleConditionBuilder.buildFilterConditions\n */\n buildFilterConditions<M extends Record<string, unknown>>(\n filter: FilterValues<Extract<keyof M, string>>,\n table: PgTable<any>,\n collectionPath: string\n ): SQL[] {\n return DrizzleConditionBuilder.buildFilterConditions(filter, table, collectionPath);\n }\n\n // =============================================================\n // DRIZZLE QUERY HELPERS\n // =============================================================\n\n /**\n * Resolves the correct Drizzle column for sorting.\n * Automatically maps owning relation property keys to their underlying foreign key column.\n */\n private resolveOrderByField(\n table: PgTable<any>,\n orderBy: string,\n collection?: EntityCollection\n ): AnyPgColumn | undefined {\n let orderByField = table[orderBy as keyof typeof table] as AnyPgColumn;\n if (!orderByField && collection) {\n const property = collection.properties[orderBy];\n if (property && property.type === \"relation\" && \"relation\" in property && property.relation?.direction === \"owning\") {\n orderByField = table[`${orderBy}_id` as keyof typeof table] as AnyPgColumn;\n }\n }\n return orderByField;\n }\n\n /**\n * Build the `with` config for Drizzle's relational query API.\n * Converts collection relations to a Drizzle-compatible `with` object.\n *\n * When `include` is provided, only those relations are loaded.\n * When `include` is absent, ALL relations are loaded (CMS path).\n *\n * Automatically detects many-to-many junction tables and nests\n * the target relation so actual entity data is returned.\n */\n private buildWithConfig(\n collection: EntityCollection,\n include?: string[]\n ): Record<string, boolean | { with: Record<string, boolean> }> {\n const resolvedRelations = resolveCollectionRelations(collection);\n const withConfig: Record<string, boolean | { with: Record<string, boolean> }> = {};\n\n const shouldInclude = (key: string) =>\n !include || include.length === 0 || include[0] === \"*\" || include.includes(key);\n\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (!shouldInclude(key)) continue;\n\n const drizzleRelName = relation.relationName || key;\n\n // Skip relations that use joinPath as they are not mapped in Drizzle schemas\n if (relation.joinPath && relation.joinPath.length > 0) {\n continue;\n }\n\n // Detect many-to-many junction tables:\n // If the relation goes through a junction table (relation.through exists or\n // the Drizzle schema maps to a junction table), we need two-level with.\n if (relation.cardinality === \"many\" && this.isJunctionRelation(relation, collection)) {\n // The Drizzle relation points to the junction table.\n // We need: { [junctionRelName]: { with: { [targetFkName]: true } } }\n // The target FK name is the relation on the junction table that points to the actual target.\n const targetFkName = this.getJunctionTargetRelationName(relation, collection);\n if (targetFkName) {\n withConfig[drizzleRelName] = { with: { [targetFkName]: true } };\n } else {\n withConfig[drizzleRelName] = true;\n }\n } else {\n withConfig[drizzleRelName] = true;\n }\n }\n\n return withConfig;\n }\n\n /**\n * Detect if a many-to-many relation uses a junction table in the Drizzle schema.\n */\n private isJunctionRelation(relation: Relation, _collection: EntityCollection): boolean {\n // If `through` is defined, it's explicitly a junction relation\n if (relation.through) return true;\n // If joinPath has an intermediate table, it's likely junction-based\n if (relation.joinPath && relation.joinPath.length > 1) return true;\n return false;\n }\n\n /**\n * Get the Drizzle relation name on the junction table that points to the actual target entity.\n * For example, for posts_tags junction, this returns \"tag_id\" (the relation pointing to tags).\n */\n private getJunctionTargetRelationName(relation: Relation, _collection: EntityCollection): string | null {\n if (relation.through) {\n // The junction relation on the junction table pointing to the target\n // uses the targetColumn name as the Drizzle relation name\n return relation.through.targetColumn.replace(/_id$/, \"_id\");\n }\n return null;\n }\n\n /**\n * Convert a db.query result row (with nested relation objects) to an Entity<M>.\n * Handles:\n * - The { id, path, values } wrapping\n * - Type normalization (dates, numbers, NaN) via normalizeDbValues\n * - Converting nested relation objects to { id, path, __type: \"relation\" } for CMS\n * - Flattening junction-table many-to-many results\n */\n private drizzleResultToEntity<M extends Record<string, unknown>>(\n row: Record<string, unknown>,\n collection: EntityCollection,\n collectionPath: string,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n databaseId?: string,\n idInfoArray?: { fieldName: string; type: \"string\" | \"number\" }[]\n ): Entity<M> {\n const resolvedRelations = resolveCollectionRelations(collection);\n\n // Normalize non-relation values (dates, numbers, etc.)\n const normalizedValues = normalizeDbValues(row as M, collection);\n\n // Convert nested relation objects to CMS-style { id, path, __type: \"relation\" }\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n const drizzleRelName = relation.relationName || key;\n const relData = row[drizzleRelName];\n\n if (relData === undefined || relData === null) continue;\n\n if (relation.cardinality === \"many\" && Array.isArray(relData)) {\n const targetCollection = relation.target();\n const targetPath = targetCollection.slug;\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdField = targetPks[0].fieldName;\n\n (normalizedValues as Record<string, unknown>)[key] = relData.map((item: Record<string, unknown>) => {\n // Handle junction table flattening:\n // Junction rows look like { post_id: 1, tag_id: { id: 5, name: \"ts\" } }\n let targetEntity = item;\n if (this.isJunctionRelation(relation, collection)) {\n // Find the nested target object in the junction row\n const nestedKey = Object.keys(item).find(\n nk => typeof item[nk] === \"object\" && item[nk] !== null && !Array.isArray(item[nk])\n );\n if (nestedKey) {\n targetEntity = item[nestedKey] as Record<string, unknown>;\n }\n }\n\n const relId = String(targetEntity[targetIdField] ?? targetEntity.id ?? targetEntity[Object.keys(targetEntity)[0]]);\n const targetValues = normalizeDbValues(targetEntity, targetCollection);\n\n return createRelationRefWithData(relId, targetPath, {\n id: relId,\n path: targetPath,\n values: targetValues,\n databaseId\n });\n });\n } else if (relation.cardinality === \"one\" && typeof relData === \"object\" && !Array.isArray(relData)) {\n const targetCollection = relation.target();\n const targetPath = targetCollection.slug;\n const targetPks = getPrimaryKeys(targetCollection, this.registry);\n const targetIdField = targetPks[0].fieldName;\n const relObj = relData as Record<string, unknown>;\n\n const relId = String(relObj[targetIdField] ?? relObj.id ?? relObj[Object.keys(relObj)[0]]);\n const targetValues = normalizeDbValues(relObj, targetCollection);\n\n (normalizedValues as Record<string, unknown>)[key] = createRelationRefWithData(relId, targetPath, {\n id: relId,\n path: targetPath,\n values: targetValues,\n databaseId\n });\n }\n }\n\n return {\n id: (idInfoArray && idInfoArray.length > 1) ? buildCompositeId(row as Record<string, unknown>, idInfoArray) : String(row[idInfo.fieldName]),\n path: collectionPath,\n values: normalizedValues as M,\n databaseId\n };\n }\n\n /**\n * Post-fetch joinPath relations for a single entity.\n * joinPath relations cannot be expressed via Drizzle's `with` config,\n * so they must be loaded separately after the primary query.\n */\n private async resolveJoinPathRelations<M extends Record<string, unknown>>(\n entity: Entity<M>,\n collection: EntityCollection,\n collectionPath: string,\n parsedId: string | number,\n databaseId?: string\n ): Promise<void> {\n const resolvedRelations = resolveCollectionRelations(collection);\n\n const promises = Object.entries(resolvedRelations)\n .filter(([key, relation]) => relation.joinPath && relation.joinPath.length > 0)\n .map(async ([key, relation]) => {\n try {\n const relatedEntities = await this.relationService.fetchRelatedEntities(\n collectionPath,\n parsedId,\n key,\n { limit: relation.cardinality === \"one\" ? 1 : undefined }\n );\n\n if (relation.cardinality === \"one\" && relatedEntities.length > 0) {\n const e = relatedEntities[0];\n (entity.values as Record<string, unknown>)[key] = createRelationRefWithData(e.id, e.path, e);\n } else if (relation.cardinality === \"many\") {\n (entity.values as Record<string, unknown>)[key] = relatedEntities.map(e =>\n createRelationRefWithData(e.id, e.path, e)\n );\n }\n } catch (e) {\n logger.warn(`Could not resolve joinPath relation '${key}'`, { error: e });\n }\n });\n\n await Promise.all(promises);\n }\n\n /**\n * Post-fetch joinPath relations for a batch of entities.\n * Uses batch fetching to avoid N+1 queries for list views.\n */\n private async resolveJoinPathRelationsBatch<M extends Record<string, unknown>>(\n entities: Entity<M>[],\n collection: EntityCollection,\n collectionPath: string,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n databaseId?: string\n ): Promise<void> {\n if (entities.length === 0) return;\n\n const resolvedRelations = resolveCollectionRelations(collection);\n\n const joinPathRelations = Object.entries(resolvedRelations)\n .filter(([key, relation]) => relation.joinPath && relation.joinPath.length > 0);\n\n if (joinPathRelations.length === 0) return;\n\n for (const [key, relation] of joinPathRelations) {\n try {\n const entityIds = entities.map(e => {\n const parsed = parseIdValues(e.id, [idInfo]);\n return parsed[idInfo.fieldName] as string | number;\n });\n\n const resultMap = await this.relationService.batchFetchRelatedEntities(\n collectionPath,\n entityIds,\n key,\n relation\n );\n\n for (const entity of entities) {\n const parsed = parseIdValues(entity.id, [idInfo]);\n const entityId = parsed[idInfo.fieldName] as string | number;\n const relatedEntity = resultMap.get(String(entityId));\n\n if (relatedEntity) {\n if (relation.cardinality === \"one\") {\n (entity.values as Record<string, unknown>)[key] = createRelationRefWithData(relatedEntity.id, relatedEntity.path, relatedEntity);\n }\n }\n }\n } catch (e) {\n logger.warn(`Could not batch resolve joinPath relation '${key}'`, { error: e });\n }\n }\n }\n\n /**\n * Resolves joinPath relations for raw REST rows and directly injects them.\n * Uses RelationService to query the database and maps results back to the flattened objects.\n */\n private async resolveJoinPathRelationsBatchRest(\n rows: Record<string, unknown>[],\n collection: EntityCollection,\n collectionPath: string,\n idInfoArray: { fieldName: string; type: \"string\" | \"number\" }[],\n include?: string[]\n ): Promise<void> {\n if (rows.length === 0) return;\n\n const resolvedRelations = resolveCollectionRelations(collection);\n const propertyKeys = new Set(Object.keys(collection.properties || {}));\n const shouldInclude = (key: string) =>\n !include || include.length === 0 || include[0] === \"*\" || include.includes(key);\n\n const joinPathRelations = Object.entries(resolvedRelations)\n .filter(([key, relation]) => relation.joinPath && relation.joinPath.length > 0 && propertyKeys.has(key) && shouldInclude(key));\n\n if (joinPathRelations.length === 0) return;\n\n const idInfo = idInfoArray[0];\n\n for (const [key, relation] of joinPathRelations) {\n try {\n // Determine the parent IDs based on the parsed string ID from the REST row\n const entityIds = rows.map(r => {\n const parsed = parseIdValues(String(r.id), idInfoArray);\n return parsed[idInfo.fieldName] as string | number;\n });\n\n if (relation.cardinality === \"one\") {\n const resultMap = await this.relationService.batchFetchRelatedEntities(\n collectionPath,\n entityIds,\n key,\n relation\n );\n\n for (const row of rows) {\n const parsed = parseIdValues(String(row.id), idInfoArray);\n const entityId = parsed[idInfo.fieldName] as string | number;\n const relatedEntity = resultMap.get(String(entityId));\n\n if (relatedEntity) {\n row[key] = {\n id: relatedEntity.id,\n ...relatedEntity.values\n };\n } else {\n row[key] = null;\n }\n }\n } else if (relation.cardinality === \"many\") {\n const resultMap = await this.batchFetchManyRelatedEntities(\n collectionPath,\n entityIds,\n key\n );\n\n for (const row of rows) {\n const parsed = parseIdValues(String(row.id), idInfoArray);\n const entityId = parsed[idInfo.fieldName] as string | number;\n const relatedList = resultMap.get(String(entityId)) || [];\n row[key] = relatedList.map(e => ({\n id: e.id,\n ...e.values\n }));\n }\n }\n } catch (e) {\n logger.warn(`Could not batch resolve joinPath relation '${key}' for REST`, { error: e });\n }\n }\n }\n\n /**\n * Convert a db.query result row to a flat REST-style object with populated relations.\n */\n private drizzleResultToRestRow(\n row: Record<string, unknown>,\n collection: EntityCollection,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n idInfoArray?: { fieldName: string; type: \"string\" | \"number\" }[]\n ): Record<string, unknown> {\n const flat: Record<string, unknown> = { id: (idInfoArray && idInfoArray.length > 1) ? buildCompositeId(row as Record<string, unknown>, idInfoArray) : String(row[idInfo.fieldName]) };\n const resolvedRelations = resolveCollectionRelations(collection);\n\n for (const [k, v] of Object.entries(row)) {\n if (k === idInfo.fieldName) continue;\n\n const relation = findRelation(resolvedRelations, k);\n if (Array.isArray(v) && relation) {\n // Many relation — flatten each nested entity, handling junction tables\n flat[k] = v.map((item: Record<string, unknown>) => {\n if (this.isJunctionRelation(relation, collection)) {\n const nestedKey = Object.keys(item).find(\n nk => typeof item[nk] === \"object\" && item[nk] !== null && !Array.isArray(item[nk])\n );\n if (nestedKey) {\n const nested = item[nestedKey] as Record<string, unknown>;\n return { id: String(nested.id ?? nested[Object.keys(nested)[0]]),\n...nested };\n }\n }\n return { id: String(item.id ?? item[Object.keys(item)[0]]),\n...item };\n });\n } else if (typeof v === \"object\" && v !== null && !Array.isArray(v) && relation) {\n // One-to-one relation — inline the object\n const relObj = v as Record<string, unknown>;\n flat[k] = { id: String(relObj.id ?? relObj[Object.keys(relObj)[0]]),\n...relObj };\n } else {\n flat[k] = v;\n }\n }\n return flat;\n }\n\n /**\n * Build db.query-compatible options from standard fetch options.\n * Handles filter, search, orderBy, limit, and cursor-based pagination.\n */\n private buildDrizzleQueryOptions<M extends Record<string, unknown>>(\n table: PgTable<any>,\n idField: AnyPgColumn,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n logical?: LogicalCondition;\n },\n collectionPath: string,\n withConfig?: Record<string, unknown>\n ): Record<string, unknown> {\n const queryOpts: Record<string, unknown> = {};\n\n if (withConfig) queryOpts.with = withConfig;\n\n // Build where conditions\n const allConditions: SQL[] = [];\n\n if (options.searchString) {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const searchConditions = DrizzleConditionBuilder.buildSearchConditions(\n options.searchString, collection.properties, table\n );\n if (searchConditions.length === 0) {\n // Return options that will produce empty results\n queryOpts.where = and(eq(idField, -99999999)); // impossible condition\n return queryOpts;\n }\n allConditions.push(DrizzleConditionBuilder.combineConditionsWithOr(searchConditions)!);\n }\n\n if (options.filter) {\n const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);\n if (filterConditions.length > 0) allConditions.push(...filterConditions);\n }\n\n if (options.logical) {\n const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);\n if (logicalCondition) allConditions.push(logicalCondition);\n }\n\n // Cursor-based pagination (startAfter)\n if (options.startAfter) {\n const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);\n if (cursorConditions.length > 0) allConditions.push(...cursorConditions);\n }\n\n if (allConditions.length > 0) {\n queryOpts.where = and(...allConditions);\n }\n\n // OrderBy\n const orderExpressions: unknown[] = [];\n if (options.orderBy) {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const orderByField = this.resolveOrderByField(table, options.orderBy, collection);\n if (orderByField) {\n orderExpressions.push(options.order === \"asc\" ? asc(orderByField) : desc(orderByField));\n }\n }\n orderExpressions.push(desc(idField));\n if (orderExpressions.length > 0) {\n queryOpts.orderBy = orderExpressions;\n }\n\n // Limit\n const limitValue = options.searchString ? (options.limit || 50) : options.limit;\n if (limitValue) queryOpts.limit = limitValue;\n\n // Offset (numeric pagination)\n if (options.offset && options.offset > 0) queryOpts.offset = options.offset;\n\n return queryOpts;\n }\n\n /**\n * Extract cursor pagination conditions from startAfter options.\n */\n private buildCursorConditions(\n table: PgTable<any>,\n idField: AnyPgColumn,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n options: { orderBy?: string; order?: \"desc\" | \"asc\"; startAfter?: Record<string, unknown> },\n collectionPath?: string\n ): SQL[] {\n if (!options.startAfter) return [];\n const cursor = options.startAfter;\n\n if (options.orderBy) {\n const collection = collectionPath ? getCollectionByPath(collectionPath, this.registry) : undefined;\n const orderByField = this.resolveOrderByField(table, options.orderBy, collection);\n if (orderByField) {\n const startAfterOrderValue = (cursor.values as Record<string, unknown> | undefined)?.[options.orderBy] ?? cursor[options.orderBy];\n const startAfterId = cursor.id ?? cursor[idInfo.fieldName];\n\n if (startAfterOrderValue !== undefined && startAfterId !== undefined) {\n if (options.order === \"asc\") {\n return [or(\n gt(orderByField, startAfterOrderValue),\n and(eq(orderByField, startAfterOrderValue), gt(idField, startAfterId))\n )!];\n } else {\n return [or(\n lt(orderByField, startAfterOrderValue),\n and(eq(orderByField, startAfterOrderValue), lt(idField, startAfterId))\n )!];\n }\n }\n }\n } else {\n const startAfterId = cursor.id ?? cursor[idInfo.fieldName];\n if (startAfterId !== undefined && startAfterId !== null) {\n const idInfoArray = [idInfo] as Array<{ fieldName: string; type: \"string\" | \"number\" }>;\n const parsedStartAfterIdObj = parseIdValues(startAfterId as string | number, idInfoArray);\n return [lt(idField, parsedStartAfterIdObj[idInfo.fieldName])];\n }\n }\n\n return [];\n }\n\n /**\n * Fetch a single entity by ID\n */\n async fetchEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n entityId: string | number,\n databaseId?: string\n ): Promise<Entity<M> | undefined> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n if (!idField) {\n throw new Error(`ID field '${idInfo.fieldName}' not found in table for collection '${collectionPath}'`);\n }\n\n const parsedIdObj = parseIdValues(entityId, idInfoArray);\n const parsedId = parsedIdObj[idInfo.fieldName];\n\n // Primary path: use db.query.findFirst with relation loading\n\n const tableName = getTableName(table);\n\n const qb = this.getQueryBuilder(tableName);\n if (qb) {\n try {\n const withConfig = this.buildWithConfig(collection);\n\n const row = await qb.findFirst({\n where: eq(idField, parsedId),\n with: withConfig\n } as Parameters<NonNullable<typeof qb>[\"findFirst\"]>[0]);\n\n if (!row) return undefined;\n\n const entity = this.drizzleResultToEntity<M>(row, collection, collectionPath, idInfo, databaseId, idInfoArray);\n\n // Post-fetch joinPath relations that Drizzle's `with` can't express\n await this.resolveJoinPathRelations(entity, collection, collectionPath, parsedId, databaseId);\n\n return entity;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"not enough information to infer relation\")) {\n logger.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);\n logger.error(\"Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.\");\n }\n logger.warn(`[EntityFetchService] db.query.findFirst failed for ${collectionPath}, falling back to db.select`, { error: e });\n }\n }\n\n // Fallback: db.select + N+1 relation loading\n const result = await this.db\n .select()\n .from(table)\n .where(eq(idField, parsedId))\n .limit(1);\n\n if (result.length === 0) return undefined;\n\n const raw = result[0] as M;\n const values = await parseDataFromServer(raw, collection, this.db, this.registry);\n\n // Load relations based on cardinality (N+1 — only used in fallback)\n const resolvedRelations = resolveCollectionRelations(collection);\n const propertyKeys = new Set(Object.keys(collection.properties));\n\n const relationPromises = Object.entries(resolvedRelations)\n .filter(([key]) => propertyKeys.has(key))\n .map(async ([key, relation]) => {\n if (relation.cardinality === \"many\") {\n const relatedEntities = await this.relationService.fetchRelatedEntities(\n collectionPath,\n parsedId,\n key,\n {}\n );\n (values as Record<string, unknown>)[key] = relatedEntities.map(e =>\n createRelationRef(e.id, e.path)\n );\n } else if (relation.cardinality === \"one\") {\n if ((values as Record<string, unknown>)[key] == null) {\n try {\n const relatedEntities = await this.relationService.fetchRelatedEntities(\n collectionPath,\n parsedId,\n key,\n { limit: 1 }\n );\n if (relatedEntities.length > 0) {\n const e = relatedEntities[0];\n (values as Record<string, unknown>)[key] = createRelationRef(e.id, e.path);\n }\n } catch (e) {\n logger.warn(`Could not resolve one-to-one relation property: ${key}`, { error: e });\n }\n }\n }\n });\n\n await Promise.all(relationPromises);\n\n return {\n id: entityId.toString(),\n path: collectionPath,\n values: values as M,\n databaseId\n };\n }\n\n /**\n * Unified method to fetch entities with optional search functionality\n */\n async fetchEntitiesWithConditions<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n vectorSearch?: VectorSearchParams;\n logical?: LogicalCondition;\n } = {}\n ): Promise<Entity<M>[]> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n if (!idField) {\n throw new Error(`ID field '${idInfo.fieldName}' not found in table for collection '${collectionPath}'`);\n }\n\n // Primary path: use db.query.findMany with relation loading\n // Skip when searchString is present (same reason as fetchCollectionForRest)\n // Skip when collection has relations — lateral JOINs are catastrophically\n // slow for large collections (7s+ for 350 rows). The db.select fallback\n // path uses batch relation resolution which is 50x faster.\n\n const tableName = getTableName(table);\n\n const qb = this.getQueryBuilder(tableName);\n const withConfig = this.buildWithConfig(collection);\n const hasRelations = withConfig && Object.keys(withConfig).length > 0;\n\n // Skip db.query path when vectorSearch is present — it doesn't support\n // custom SELECT expressions needed for the _distance column.\n if (qb && !options.searchString && !hasRelations && !options.vectorSearch) {\n try {\n const queryOpts = this.buildDrizzleQueryOptions<M>(\n table, idField, idInfo, options, collectionPath, undefined\n );\n\n\n const results = await qb.findMany(queryOpts as Parameters<NonNullable<typeof qb>[\"findMany\"]>[0]);\n\n const entities = (results as Record<string, unknown>[]).map(row =>\n this.drizzleResultToEntity<M>(row, collection, collectionPath, idInfo, options.databaseId, idInfoArray)\n );\n\n return entities;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"not enough information to infer relation\")) {\n logger.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);\n logger.error(\"Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.\");\n }\n logger.warn(`[EntityFetchService] db.query.findMany failed for ${collectionPath}, falling back to db.select`, { error: e });\n }\n }\n\n // Fallback: db.select + processEntityResults (N+1 for relations)\n // When vectorSearch is present, add _distance to the SELECT.\n let vectorMeta: { orderBy: SQL; filter?: SQL; distanceSelect: SQL } | undefined;\n if (options.vectorSearch) {\n vectorMeta = DrizzleConditionBuilder.buildVectorSearchConditions(table, options.vectorSearch);\n }\n\n let query = vectorMeta\n ? this.db.select({ table_row: table,\n_distance: vectorMeta.distanceSelect }).from(table).$dynamic()\n : this.db.select().from(table).$dynamic();\n const allConditions: SQL[] = [];\n\n if (options.searchString) {\n const searchConditions = DrizzleConditionBuilder.buildSearchConditions(\n options.searchString, collection.properties, table\n );\n if (searchConditions.length === 0) return [];\n allConditions.push(DrizzleConditionBuilder.combineConditionsWithOr(searchConditions)!);\n }\n\n if (options.filter) {\n const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);\n if (filterConditions.length > 0) allConditions.push(...filterConditions);\n }\n\n if (options.logical) {\n const logicalCondition = DrizzleConditionBuilder.buildLogicalConditions(options.logical, table, collectionPath);\n if (logicalCondition) allConditions.push(logicalCondition);\n }\n\n // Vector distance threshold filter\n if (vectorMeta?.filter) {\n allConditions.push(vectorMeta.filter);\n }\n\n if (allConditions.length > 0) {\n const finalCondition = DrizzleConditionBuilder.combineConditionsWithAnd(allConditions);\n if (finalCondition) query = query.where(finalCondition);\n }\n\n const orderExpressions = [];\n // Vector search overrides ORDER BY with distance (ascending = closest first)\n if (vectorMeta) {\n orderExpressions.push(asc(vectorMeta.orderBy));\n } else if (options.orderBy) {\n const orderByField = this.resolveOrderByField(table, options.orderBy, collection);\n if (orderByField) {\n orderExpressions.push(options.order === \"asc\" ? asc(orderByField) : desc(orderByField));\n }\n }\n orderExpressions.push(desc(idField));\n if (orderExpressions.length > 0) query = query.orderBy(...orderExpressions);\n\n if (options.startAfter) {\n const cursorConditions = this.buildCursorConditions(table, idField, idInfo, options, collectionPath);\n if (cursorConditions.length > 0) {\n allConditions.push(...cursorConditions);\n const finalCondition = DrizzleConditionBuilder.combineConditionsWithAnd(allConditions);\n if (finalCondition) query = query.where(finalCondition);\n }\n }\n\n const limitValue = options.vectorSearch\n ? (options.limit || 10)\n : options.searchString ? (options.limit || 50) : options.limit;\n if (limitValue) query = query.limit(limitValue);\n\n // Offset (numeric pagination)\n if (options.offset && options.offset > 0) query = query.offset(options.offset);\n\n const rawResults = await query;\n\n // When vector search is active, unwrap the nested select shape and\n // attach _distance to each entity's values.\n const results = vectorMeta\n ? (rawResults as { table_row: Record<string, unknown>; _distance: unknown }[]).map(r => ({\n ...r.table_row,\n _distance: typeof r._distance === \"number\" ? r._distance : parseFloat(String(r._distance))\n }))\n : rawResults as Record<string, unknown>[];\n\n return this.processEntityResults<M>(results, collection, collectionPath, idInfo, options.databaseId, false, idInfoArray);\n }\n\n /**\n * Fallback path used when db.query is unavailable.\n * The primary path uses drizzleResultToEntity which handles relation\n * mapping without N+1 queries.\n *\n * Process raw database results into Entity objects with relations.\n */\n private async processEntityResults<M extends Record<string, unknown>>(\n results: Record<string, unknown>[],\n collection: EntityCollection,\n collectionPath: string,\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n databaseId?: string,\n skipRelations = false,\n idInfoArray?: { fieldName: string; type: \"string\" | \"number\" }[]\n ): Promise<Entity<M>[]> {\n if (results.length === 0) return [];\n\n // First pass: parse all entities WITHOUT per-entity relation queries.\n // We deliberately omit db/registry so parseDataFromServer only does type\n // coercion (dates, numbers, FK→relation stubs for owning relations) and\n // does NOT issue individual SQL queries for inverse relations. The second\n // pass below batch-loads all inverse/many relations in O(1) queries per\n // relation type, avoiding the N+1 that plagued the old path.\n const entitiesWithValues = await Promise.all(results.map(async (entity: Record<string, unknown>) => {\n const values = await parseDataFromServer(entity as M, collection);\n return {\n entity,\n values,\n id: (idInfoArray && idInfoArray.length > 1) ? buildCompositeId(entity as Record<string, unknown>, idInfoArray!) : String(entity[idInfo.fieldName]),\n path: collectionPath\n };\n }));\n\n if (!skipRelations) {\n // Second pass: batch load missing one-to-one relations\n const resolvedRelations = resolveCollectionRelations(collection);\n const propertyKeys = new Set(Object.keys(collection.properties));\n\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (!propertyKeys.has(key) || relation.cardinality !== \"one\") continue;\n\n const entitiesMissingRelation = entitiesWithValues.filter(item => {\n const val = (item.values as Record<string, unknown>)[key];\n if (val == null) return true;\n if (typeof val === \"object\" && !Array.isArray(val) && (val as Record<string, unknown>).__type === \"relation\" && (val as Record<string, unknown>).data == null) return true;\n return false;\n });\n\n if (entitiesMissingRelation.length === 0) continue;\n\n try {\n const entityIds = entitiesMissingRelation.map(item => item.entity[idInfo.fieldName] as string | number);\n const relationResults = await this.relationService.batchFetchRelatedEntities(\n collectionPath,\n entityIds,\n key,\n relation\n );\n\n entitiesMissingRelation.forEach(item => {\n const entityId = item.entity[idInfo.fieldName] as string | number;\n const relatedEntity = relationResults.get(String(entityId));\n if (relatedEntity) {\n (item.values as Record<string, unknown>)[key] = createRelationRefWithData(relatedEntity.id, relatedEntity.path, relatedEntity);\n }\n });\n } catch (e) {\n logger.warn(`Could not batch load one-to-one relation property: ${key}`, { error: e });\n }\n }\n\n // Batch load many-cardinality relations (1 query per relation type\n // instead of N queries per entity)\n const manyRelations = Object.entries(resolvedRelations)\n .filter(([key, relation]) => propertyKeys.has(key) && relation.cardinality === \"many\");\n\n for (const [key, relation] of manyRelations) {\n try {\n const entityIds = entitiesWithValues.map(item => item.entity[idInfo.fieldName] as string | number);\n const relationResults = await this.relationService.batchFetchRelatedEntitiesMany(\n collectionPath,\n entityIds,\n key,\n relation\n );\n\n entitiesWithValues.forEach(item => {\n const entityId = String(item.entity[idInfo.fieldName]);\n const relatedEntities = relationResults.get(entityId) || [];\n (item.values as Record<string, unknown>)[key] = relatedEntities.map(e =>\n createRelationRefWithData(e.id, e.path, e)\n );\n });\n } catch (e) {\n logger.warn(`Could not batch load many relation property: ${key}`, { error: e });\n }\n }\n }\n\n return entitiesWithValues.map(item => ({\n id: item.id,\n path: item.path,\n values: item.values as M,\n databaseId\n }));\n }\n\n /**\n * Fetch a collection of entities\n */\n async fetchCollection<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n vectorSearch?: VectorSearchParams;\n } = {}\n ): Promise<Entity<M>[]> {\n // Handle multi-segment paths by resolving through relations\n if (collectionPath.includes(\"/\")) {\n return this.fetchCollectionFromPath<M>(collectionPath, options);\n }\n\n return this.fetchEntitiesWithConditions<M>(collectionPath, options);\n }\n\n /**\n * Search entities by text\n */\n async searchEntities<M extends Record<string, unknown>>(\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 } = {}\n ): Promise<Entity<M>[]> {\n return this.fetchEntitiesWithConditions<M>(collectionPath, {\n ...options,\n searchString\n });\n }\n\n /**\n * Fetch collection from multi-segment path\n */\n private async fetchCollectionFromPath<M extends Record<string, unknown>>(\n path: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<Entity<M>[]> {\n const pathSegments = path.split(\"/\").filter(p => p && p !== \"undefined\");\n\n if (pathSegments.length < 3 || pathSegments.length % 2 === 0) {\n throw new Error(`Invalid relation path: ${path}. Expected format: collection/id/relation`);\n }\n\n const rootCollectionPath = pathSegments[0];\n let currentCollection = getCollectionByPath(rootCollectionPath, this.registry);\n let currentEntityId: string | number = pathSegments[1];\n\n for (let i = 2; i < pathSegments.length; i += 2) {\n const relationKey = pathSegments[i];\n const resolvedRelations = resolveCollectionRelations(currentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n\n if (!relation) {\n throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);\n }\n\n if (i === pathSegments.length - 1) {\n const entities = await this.relationService.fetchRelatedEntities<M>(\n currentCollection.slug,\n currentEntityId,\n relationKey,\n options\n );\n // Remap entity paths to use the full subcollection path (e.g., \"authors/19/posts\")\n // instead of just the target collection slug (\"posts\"). This ensures\n // delete/update operations use the correct path for WebSocket notification matching.\n for (const entity of entities) {\n entity.path = path;\n }\n return entities;\n }\n\n if (i + 1 < pathSegments.length) {\n const nextEntityId = pathSegments[i + 1];\n currentCollection = relation.target();\n currentEntityId = nextEntityId;\n }\n }\n\n throw new Error(`Unable to resolve path: ${path}`);\n }\n\n /**\n * Count entities in a collection\n */\n async countEntities<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<number> {\n if (collectionPath.includes(\"/\")) {\n return this.countEntitiesFromPath<M>(collectionPath, options);\n }\n\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n\n let query = this.db.select({ count: count() }).from(table).$dynamic();\n const allConditions: SQL[] = [];\n\n if (options.searchString) {\n const searchConditions = DrizzleConditionBuilder.buildSearchConditions(\n options.searchString, collection.properties, table\n );\n if (searchConditions.length === 0) return 0;\n allConditions.push(DrizzleConditionBuilder.combineConditionsWithOr(searchConditions)!);\n }\n\n if (options.filter) {\n const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);\n if (filterConditions.length > 0) allConditions.push(...filterConditions);\n }\n\n if (allConditions.length > 0) {\n const finalCondition = DrizzleConditionBuilder.combineConditionsWithAnd(allConditions);\n if (finalCondition) query = query.where(finalCondition);\n }\n\n const result = await query;\n return Number(result[0]?.count || 0);\n }\n\n /**\n * Count entities from multi-segment path\n */\n private async countEntitiesFromPath<M extends Record<string, unknown>>(\n path: string,\n options: { filter?: FilterValues<Extract<keyof M, string>>; databaseId?: string } = {}\n ): Promise<number> {\n const pathSegments = path.split(\"/\").filter(p => p && p !== \"undefined\");\n\n if (pathSegments.length < 3 || pathSegments.length % 2 === 0) {\n throw new Error(`Invalid relation path: ${path}`);\n }\n\n const rootCollectionPath = pathSegments[0];\n let currentCollection = getCollectionByPath(rootCollectionPath, this.registry);\n let currentEntityId: string | number = pathSegments[1];\n\n for (let i = 2; i < pathSegments.length; i += 2) {\n const relationKey = pathSegments[i];\n const resolvedRelations = resolveCollectionRelations(currentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n\n if (!relation) {\n throw new Error(`Relation '${relationKey}' not found`);\n }\n\n if (i === pathSegments.length - 1) {\n return this.relationService.countRelatedEntities(\n currentCollection.slug,\n currentEntityId,\n relationKey,\n options\n );\n }\n\n if (i + 1 < pathSegments.length) {\n currentCollection = relation.target();\n currentEntityId = pathSegments[i + 1];\n }\n }\n\n throw new Error(`Unable to count for path: ${path}`);\n }\n\n /**\n * Check if a field value is unique\n */\n async checkUniqueField(\n collectionPath: string,\n fieldName: string,\n value: unknown,\n excludeEntityId?: string,\n _databaseId?: string\n ): Promise<boolean> {\n if (value === undefined || value === null) return true;\n\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n const field = table[fieldName as keyof typeof table] as AnyPgColumn;\n\n if (!field) return true;\n\n const parsedExcludeId = excludeEntityId ? parseIdValues(excludeEntityId, idInfoArray)[idInfo.fieldName] : undefined;\n const conditions = DrizzleConditionBuilder.buildUniqueFieldCondition(\n field,\n value,\n idField,\n parsedExcludeId\n );\n\n const result = await this.db\n .select({ count: count() })\n .from(table)\n .where(and(...conditions));\n\n const countResult = Number(result[0]?.count || 0);\n return countResult === 0;\n }\n\n /**\n * Get the RelationService instance for external use\n */\n getRelationService(): RelationService {\n return this.relationService;\n }\n\n // =============================================================\n // REST API INCLUDE-AWARE METHODS\n // =============================================================\n\n /**\n * Fetch a collection of entities with optional relation includes.\n * When `include` is provided, only the specified relations are populated\n * with full entity data (not just { id, path, __type }).\n * When `include` is absent, no relation queries are made (fast path).\n *\n * @param include - Array of relation keys to populate, or [\"*\"] for all\n */\n async fetchCollectionForRest<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n vectorSearch?: VectorSearchParams;\n } = {},\n include?: string[]\n ): Promise<Record<string, unknown>[]> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n // Primary path: use db.query.findMany\n // NOTE: Skip db.query path when searchString is present because\n // Drizzle's relational query API doesn't properly apply raw SQL\n // ILIKE conditions — the fallback db.select path handles them correctly.\n\n const tableName = getTableName(table);\n\n const qb = this.getQueryBuilder(tableName);\n // Skip db.query path when vectorSearch is present — needs custom SELECT\n if (qb && !options.searchString && !options.vectorSearch) {\n try {\n const withConfig = (include && include.length > 0)\n ? this.buildWithConfig(collection, include)\n : undefined;\n\n const queryOpts = this.buildDrizzleQueryOptions<M>(\n table, idField, idInfo, options, collectionPath, withConfig\n );\n\n\n const results = await qb.findMany(queryOpts as Parameters<NonNullable<typeof qb>[\"findMany\"]>[0]);\n\n const restRows = (results as Record<string, unknown>[]).map(row =>\n this.drizzleResultToRestRow(row, collection, idInfo, idInfoArray)\n );\n\n // Drizzle relational query API doesn't resolve joinPath relations, fetch manually\n await this.resolveJoinPathRelationsBatchRest(restRows, collection, collectionPath, idInfoArray, include);\n\n return restRows;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"not enough information to infer relation\")) {\n logger.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);\n logger.error(\"Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.\");\n }\n logger.warn(`[fetchCollectionForRest] db.query.findMany failed for ${collectionPath}, falling back`, { error: e });\n }\n }\n\n // Fallback: fetch base entities without relations\n const entities = await this.fetchEntitiesWithConditionsRaw<M>(collectionPath, options);\n\n if (!include || include.length === 0) {\n return entities.map(entity => ({\n id: (idInfoArray.length > 1) ? buildCompositeId(entity as Record<string, unknown>, idInfoArray) : String(entity[idInfo.fieldName]),\n ...entity\n }));\n }\n\n // Fallback relation loading via batch\n const resolvedRelations = resolveCollectionRelations(collection);\n const propertyKeys = new Set(Object.keys(collection.properties || {}));\n const shouldInclude = (key: string) =>\n include[0] === \"*\" || include.includes(key);\n\n const entityIds = entities.map(e => e[idInfo.fieldName] as string | number);\n\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (!propertyKeys.has(key) || !shouldInclude(key) || relation.cardinality !== \"one\") continue;\n try {\n const batchResults = await this.relationService.batchFetchRelatedEntities(\n collectionPath, entityIds, key, relation\n );\n for (const entity of entities) {\n const eid = entity[idInfo.fieldName] as string | number;\n const related = batchResults.get(String(eid));\n if (related) {\n (entity as Record<string, unknown>)[key] = { id: related.id,\n...related.values };\n }\n }\n } catch (e) {\n logger.warn(`[include] Failed to batch load one-to-one '${key}'`, { error: e });\n }\n }\n\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (!propertyKeys.has(key) || !shouldInclude(key) || relation.cardinality !== \"many\") continue;\n try {\n const batchResults = await this.batchFetchManyRelatedEntities(\n collectionPath, entityIds, key\n );\n for (const entity of entities) {\n const eid = entity[idInfo.fieldName] as string | number;\n const relatedList = batchResults.get(String(eid)) || [];\n (entity as Record<string, unknown>)[key] = relatedList.map(e => ({\n id: e.id,\n...e.values\n }));\n }\n } catch (e) {\n logger.warn(`[include] Failed to batch load many '${key}'`, { error: e });\n }\n }\n\n return entities.map(entity => ({\n id: (idInfoArray.length > 1) ? buildCompositeId(entity as Record<string, unknown>, idInfoArray) : String(entity[idInfo.fieldName]),\n ...entity\n }));\n }\n\n /**\n * Fetch a single entity with optional relation includes for REST API.\n */\n async fetchEntityForRest<M extends Record<string, unknown>>(\n collectionPath: string,\n entityId: string | number,\n include?: string[],\n databaseId?: string\n ): Promise<Record<string, unknown> | null> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n const parsedIdObj = parseIdValues(entityId, idInfoArray);\n const parsedId = parsedIdObj[idInfo.fieldName];\n\n // Primary path: use db.query.findFirst\n\n const tableName = getTableName(table);\n\n const qb = this.getQueryBuilder(tableName);\n if (qb) {\n try {\n const withConfig = (include && include.length > 0)\n ? this.buildWithConfig(collection, include)\n : undefined;\n\n\n const row = await qb.findFirst({\n where: eq(idField, parsedId),\n ...(withConfig ? { with: withConfig } : {})\n } as Parameters<NonNullable<typeof qb>[\"findFirst\"]>[0]);\n\n if (!row) return null;\n\n const restRow = this.drizzleResultToRestRow(row, collection, idInfo, idInfoArray);\n\n // Drizzle relational query API doesn't resolve joinPath relations, fetch manually\n await this.resolveJoinPathRelationsBatchRest([restRow], collection, collectionPath, idInfoArray, include);\n\n return restRow;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"not enough information to infer relation\")) {\n logger.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);\n logger.error(\"Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.\");\n }\n logger.warn(`[fetchEntityForRest] db.query.findFirst failed for ${collectionPath}, falling back`, { error: e });\n }\n }\n\n // Fallback: db.select + N+1 relation loading\n const result = await this.db\n .select()\n .from(table)\n .where(eq(idField, parsedId))\n .limit(1);\n\n if (result.length === 0) return null;\n\n const raw = result[0] as Record<string, unknown>;\n const flatEntity: Record<string, unknown> = { id: (idInfoArray.length > 1) ? buildCompositeId(raw as Record<string, unknown>, idInfoArray) : String(raw[idInfo.fieldName]),\n...raw };\n\n if (!include || include.length === 0) {\n return flatEntity;\n }\n\n // Fallback relation population\n const resolvedRelations = resolveCollectionRelations(collection);\n const propertyKeys = new Set(Object.keys(collection.properties || {}));\n const shouldInclude = (key: string) =>\n include[0] === \"*\" || include.includes(key);\n\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (!propertyKeys.has(key) || !shouldInclude(key)) continue;\n\n try {\n const relatedEntities = await this.relationService.fetchRelatedEntities(\n collectionPath, parsedId, key, {}\n );\n\n if (relation.cardinality === \"one\") {\n if (relatedEntities.length > 0) {\n const e = relatedEntities[0];\n flatEntity[key] = { id: e.id,\n...e.values };\n }\n } else {\n flatEntity[key] = relatedEntities.map(e => ({\n id: e.id,\n...e.values\n }));\n }\n } catch (e) {\n logger.warn(`[include] Failed to load relation '${key}'`, { error: e });\n }\n }\n\n return flatEntity;\n }\n\n /**\n * Fetch raw rows without any relation processing (for REST fast path)\n */\n private async fetchEntitiesWithConditionsRaw<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n vectorSearch?: VectorSearchParams;\n } = {}\n ): Promise<Record<string, unknown>[]> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n let vectorMeta: { orderBy: SQL; filter?: SQL; distanceSelect: SQL } | undefined;\n if (options.vectorSearch) {\n vectorMeta = DrizzleConditionBuilder.buildVectorSearchConditions(table, options.vectorSearch);\n }\n\n let query = vectorMeta\n ? this.db.select({ table_row: table,\n_distance: vectorMeta.distanceSelect }).from(table).$dynamic()\n : this.db.select().from(table).$dynamic();\n const allConditions: SQL[] = [];\n\n if (options.searchString) {\n const searchConditions = DrizzleConditionBuilder.buildSearchConditions(\n options.searchString, collection.properties, table\n );\n if (searchConditions.length === 0) return [];\n allConditions.push(DrizzleConditionBuilder.combineConditionsWithOr(searchConditions)!);\n }\n\n if (options.filter) {\n const filterConditions = this.buildFilterConditions(options.filter, table, collectionPath);\n if (filterConditions.length > 0) allConditions.push(...filterConditions);\n }\n\n if (vectorMeta?.filter) {\n allConditions.push(vectorMeta.filter);\n }\n\n if (allConditions.length > 0) {\n const finalCondition = DrizzleConditionBuilder.combineConditionsWithAnd(allConditions);\n if (finalCondition) query = query.where(finalCondition);\n }\n\n const orderExpressions = [];\n if (vectorMeta) {\n orderExpressions.push(asc(vectorMeta.orderBy));\n } else if (options.orderBy) {\n const orderByField = this.resolveOrderByField(table, options.orderBy, collection);\n if (orderByField) {\n orderExpressions.push(options.order === \"asc\" ? asc(orderByField) : desc(orderByField));\n }\n }\n orderExpressions.push(desc(idField));\n if (orderExpressions.length > 0) query = query.orderBy(...orderExpressions);\n\n const limitValue = options.vectorSearch\n ? (options.limit || 10)\n : options.searchString ? (options.limit || 50) : options.limit;\n if (limitValue) query = query.limit(limitValue);\n\n // Offset (numeric pagination)\n if (options.offset && options.offset > 0) query = query.offset(options.offset);\n\n const rawResults = await query;\n\n if (vectorMeta) {\n return (rawResults as { table_row: Record<string, unknown>; _distance: unknown }[]).map(r => ({\n ...r.table_row,\n _distance: typeof r._distance === \"number\" ? r._distance : parseFloat(String(r._distance))\n }));\n }\n\n return rawResults as Record<string, unknown>[];\n }\n\n /**\n * Check if the Drizzle instance has the relational query API available\n * for a given collection path.\n * Note: Primary path now uses inline `getQueryBuilder()` checks.\n */\n private hasDrizzleQueryAPI(collectionPath: string): boolean {\n\n const qb = this.getQueryBuilder(\"__probe__\");\n if (!qb) {\n // If getQueryBuilder returns undefined even for a probe, query API is not available\n return false;\n }\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const tableName = getTableName(table);\n return !!this.getQueryBuilder(tableName);\n }\n\n /**\n * Attempt to use Drizzle's relational query API (db.query.<table>.findMany)\n * for efficient JOIN-based relation loading.\n * Returns null if the API is not available or the query fails.\n * Note: Primary path now uses `buildWithConfig` + `buildDrizzleQueryOptions`.\n */\n private async fetchWithDrizzleQuery<M extends Record<string, unknown>>(\n collectionPath: string,\n collection: EntityCollection,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n },\n include: string[],\n idInfo: { fieldName: string; type: \"string\" | \"number\" },\n idInfoArray?: { fieldName: string; type: \"string\" | \"number\" }[]\n ): Promise<Record<string, unknown>[] | null> {\n try {\n\n const table = getTableForCollection(collection, this.registry);\n const tableName = getTableName(table);\n const queryTarget = this.getQueryBuilder(tableName);\n\n if (!queryTarget?.findMany) return null;\n\n // Build the `with` config from include array\n const resolvedRelations = resolveCollectionRelations(collection);\n const withConfig: Record<string, boolean> = {};\n for (const [key, relation] of Object.entries(resolvedRelations)) {\n if (include[0] === \"*\" || include.includes(key)) {\n // Use the Drizzle relation name (from the schema)\n const drizzleRelName = relation.relationName || key;\n withConfig[drizzleRelName] = true;\n }\n }\n\n // Build query options\n const queryOpts: Record<string, unknown> = { with: withConfig };\n if (options.limit) queryOpts.limit = options.limit;\n\n // Build where clause\n if (options.filter) {\n const filterConditions = this.buildFilterConditions(\n options.filter, table, collectionPath\n );\n if (filterConditions.length > 0) {\n queryOpts.where = and(...filterConditions);\n }\n }\n\n // Build orderBy\n if (options.orderBy) {\n const orderByField = this.resolveOrderByField(table, options.orderBy, collection);\n if (orderByField) {\n queryOpts.orderBy = options.order === \"asc\" ? asc(orderByField) : desc(orderByField);\n }\n }\n\n\n const results = await queryTarget.findMany(queryOpts as Parameters<NonNullable<typeof queryTarget>[\"findMany\"]>[0]);\n\n // Flatten the nested Drizzle results into REST format\n return results.map((row: Record<string, unknown>) => {\n const flat: Record<string, unknown> = { id: (idInfoArray && idInfoArray.length > 1) ? buildCompositeId(row as Record<string, unknown>, idInfoArray) : String(row[idInfo.fieldName]) };\n for (const [k, v] of Object.entries(row)) {\n if (k === idInfo.fieldName) continue;\n if (Array.isArray(v)) {\n // Many relation — flatten each nested entity\n flat[k] = v.map((item: Record<string, unknown>) => {\n // Junction table rows may have the target nested, flatten those\n const keys = Object.keys(item);\n // If it looks like a junction row (only FKs + nested objects), extract nested\n const nestedObj = keys.find(nk => typeof item[nk] === \"object\" && item[nk] !== null && !Array.isArray(item[nk]));\n if (nestedObj && keys.length <= 3) {\n const nested = item[nestedObj] as Record<string, unknown>;\n return { id: String(nested.id ?? nested[Object.keys(nested)[0]]),\n...nested };\n }\n return { id: String(item.id ?? item[Object.keys(item)[0]]),\n...item };\n });\n } else if (typeof v === \"object\" && v !== null) {\n // One-to-one relation — inline the object\n const relObj = v as Record<string, unknown>;\n flat[k] = { id: String(relObj.id ?? relObj[Object.keys(relObj)[0]]),\n...relObj };\n } else {\n flat[k] = v;\n }\n }\n return flat;\n });\n } catch (e) {\n logger.warn(`[include] Drizzle relational query failed for '${collectionPath}', falling back`, { error: e });\n return null;\n }\n }\n\n /**\n * Fallback path used when db.query is unavailable.\n * The primary path uses db.query.findMany with `with` config, which\n * loads all relations in a single query.\n *\n * Batch fetch many-to-many related entities for multiple parent IDs.\n * Groups results by parent ID to avoid N+1.\n */\n private async batchFetchManyRelatedEntities(\n parentCollectionPath: string,\n parentIds: (string | number)[],\n relationKey: string\n ): Promise<Map<string, Entity[]>> {\n if (parentIds.length === 0) return new Map();\n\n // Resolve the relation definition so we can use the true batch method\n const collection = getCollectionByPath(parentCollectionPath, this.registry);\n const resolvedRelations = resolveCollectionRelations(collection);\n const relation = resolvedRelations[relationKey];\n\n if (!relation) {\n logger.warn(`[batchFetchManyRelatedEntities] Relation '${relationKey}' not found, skipping`);\n return new Map();\n }\n\n // Delegate to RelationService.batchFetchRelatedEntitiesMany which\n // uses a single SQL query with IN(...) — O(1) instead of O(N).\n return this.relationService.batchFetchRelatedEntitiesMany(\n parentCollectionPath,\n parentIds,\n relationKey,\n relation\n );\n }\n}\n","/**\n * Shared PostgreSQL error extraction and user-friendly message formatting.\n *\n * Drizzle wraps native PG errors in a `.cause` chain. These utilities\n * unwrap that chain to get the real PostgreSQL error (identified by a\n * 5-character alphanumeric `code` such as `42P01`) and translate it into\n * a message that is safe and helpful to show to end-users.\n */\n\nimport { logger } from \"@rebasepro/server-core\";\n\n/** Shape of PostgreSQL errors with diagnostic metadata. */\nexport interface PostgresError extends Error {\n code?: string;\n detail?: string;\n hint?: string;\n constraint?: string;\n column?: string;\n table?: string;\n dataType?: string;\n cause?: unknown;\n}\n\n/**\n * Extract the underlying PostgreSQL error from a Drizzle wrapper.\n * Drizzle wraps PG errors in a `cause` property — this function\n * recursively walks the chain until it finds an object with a PG\n * error code (5-char alphanumeric, e.g. `42P01`).\n */\nexport function extractPgError(error: unknown): PostgresError | null {\n if (!error || typeof error !== \"object\") return null;\n if (!(error instanceof Error)) {\n // Check non-Error objects for a cause chain (Drizzle sometimes wraps oddly)\n if (\"cause\" in error && (error as Record<string, unknown>).cause && typeof (error as Record<string, unknown>).cause === \"object\") {\n return extractPgError((error as Record<string, unknown>).cause);\n }\n return null;\n }\n\n // Check if the error itself has a PG error code\n if (\"code\" in error && typeof (error as PostgresError).code === \"string\" && /^[0-9A-Z]{5}$/.test((error as PostgresError).code!)) {\n return error as PostgresError;\n }\n\n // Check the cause chain (Drizzle wraps PG errors)\n if (error.cause && typeof error.cause === \"object\") {\n return extractPgError(error.cause);\n }\n\n return null;\n}\n\n/**\n * Walk the error cause chain and return the deepest meaningful message.\n */\nexport function extractCauseMessage(error: unknown): string | null {\n if (!error || typeof error !== \"object\") return null;\n if (!(error instanceof Error)) return null;\n\n if (error.cause && typeof error.cause === \"object\") {\n const deeper = extractCauseMessage(error.cause);\n if (deeper) return deeper;\n // The cause itself has a message\n if (error.cause instanceof Error && error.cause.message) {\n return error.cause.message;\n }\n }\n return null;\n}\n\n/**\n * Translate a raw PostgreSQL error into a user-friendly message.\n *\n * @param pgError - The extracted PostgreSQL error (from {@link extractPgError})\n * @param context - A human-readable context string (e.g. collection slug or path)\n * @returns An object with a `message` safe for the client and the PG `code`.\n */\nexport function pgErrorToFriendlyMessage(pgError: PostgresError, context: string): { message: string; code: string } {\n const detail = pgError.detail as string | undefined;\n const hint = pgError.hint as string | undefined;\n const constraint = pgError.constraint as string | undefined;\n const column = pgError.column as string | undefined;\n const table = pgError.table as string | undefined;\n const dataType = pgError.dataType as string | undefined;\n const pgMessage = pgError.message || \"Unknown database error\";\n const code = pgError.code || \"UNKNOWN\";\n\n const suffix = hint ? ` Hint: ${hint}` : \"\";\n const tableRef = table ?? context;\n\n switch (pgError.code) {\n case \"23503\": // foreign_key_violation\n return {\n message: detail\n ? `Foreign key constraint violated: ${detail}${suffix}`\n : `Cannot complete operation: a foreign key constraint${constraint ? ` (${constraint})` : \"\"} was violated in \"${context}\".${suffix}`,\n code\n };\n case \"23505\": // unique_violation\n return {\n message: detail\n ? `Duplicate value: ${detail}${suffix}`\n : `Cannot complete operation: a unique constraint${constraint ? ` (${constraint})` : \"\"} was violated in \"${context}\".${suffix}`,\n code\n };\n case \"23502\": // not_null_violation\n return {\n message: `Missing required field: \"${column ?? \"unknown\"}\" in \"${tableRef}\" cannot be empty.${suffix}`,\n code\n };\n case \"23514\": // check_violation\n return {\n message: `Validation failed: a check constraint${constraint ? ` (${constraint})` : \"\"} was violated in \"${context}\".${suffix}`,\n code\n };\n case \"22P02\": // invalid_text_representation (e.g. invalid UUID, wrong enum value)\n return {\n message: `Invalid data format in \"${context}\": ${pgMessage}${suffix}`,\n code\n };\n case \"22001\": // string_data_right_truncation (value too long)\n return {\n message: `Value too long for column \"${column ?? \"unknown\"}\" in \"${tableRef}\": ${pgMessage}${suffix}`,\n code\n };\n case \"22003\": // numeric_value_out_of_range\n return {\n message: `Numeric value out of range for column \"${column ?? \"unknown\"}\" in \"${tableRef}\": ${pgMessage}${suffix}`,\n code\n };\n case \"42703\": // undefined_column\n return {\n message: `Unknown column in \"${tableRef}\": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`,\n code\n };\n case \"42P01\": // undefined_table\n return {\n message: `Table not found for \"${context}\": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`,\n code\n };\n case \"42501\": // insufficient_privilege\n return {\n message: `Permission denied on \"${tableRef}\". Check your database credentials and RLS policies.${suffix}`,\n code\n };\n case \"28000\": // invalid_authorization_specification\n return {\n message: `Authorization failed for \"${context}\". Check your database credentials.${suffix}`,\n code\n };\n default: {\n // Unhandled PG code — still surface the actual database message\n const parts = [`Database error in \"${context}\" [${code}]: ${pgMessage}`];\n if (detail) parts.push(`Detail: ${detail}`);\n if (column) parts.push(`Column: ${column}`);\n if (dataType) parts.push(`Data type: ${dataType}`);\n if (constraint) parts.push(`Constraint: ${constraint}`);\n if (hint) parts.push(`Hint: ${hint}`);\n return { message: parts.join(\". \"), code };\n }\n }\n}\n\n/**\n * Sanitize any error into a message safe and helpful for the client.\n *\n * Extracts the PG error from the Drizzle cause chain when possible;\n * falls back to a generic message that doesn't leak SQL.\n *\n * @param error - The raw caught error\n * @param context - A human-readable context string (e.g. collection path)\n * @returns An object with `message` (user-friendly) and optional `code` (PG code).\n */\nexport function sanitizeErrorForClient(error: unknown, context: string): { message: string; code?: string } {\n // ── Always log the full, unsanitized error server-side ──────────\n const pgError = extractPgError(error);\n\n if (pgError) {\n logger.error(`[PG ${pgError.code}] Error in \"${context}\"`, {\n code: pgError.code,\n message: pgError.message,\n detail: pgError.detail,\n hint: pgError.hint,\n column: pgError.column,\n table: pgError.table,\n constraint: pgError.constraint,\n dataType: pgError.dataType,\n // Also log the outer Drizzle wrapper message for full context\n drizzleMessage: error instanceof Error ? error.message : String(error)\n });\n return pgErrorToFriendlyMessage(pgError, context);\n }\n\n // No PG error found — log the raw error as-is\n logger.error(`Database error in \"${context}\" (no PG error extracted)`, {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n cause: error instanceof Error && error.cause\n ? (error.cause instanceof Error ? error.cause.message : String(error.cause))\n : undefined\n });\n\n // Try to get the deepest cause message\n const causeMessage = extractCauseMessage(error);\n if (causeMessage) {\n return { message: `Database error in \"${context}\": ${causeMessage}` };\n }\n\n // Last resort — generic message, never leak raw SQL\n return { message: `Could not load data for \"${context}\". Check server logs for details.` };\n}\n","import { eq, and } from \"drizzle-orm\";\nimport { AnyPgColumn } from \"drizzle-orm/pg-core\";\n// import { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { Entity, EntityCollection, Properties, Relation } from \"@rebasepro/types\";\nimport { getTableName, resolveCollectionRelations, findRelation } from \"@rebasepro/common\";\nimport { DrizzleConditionBuilder } from \"../utils/drizzle-conditions\";\nimport {\n getCollectionByPath,\n getTableForCollection,\n getPrimaryKeys,\n parseIdValues,\n buildCompositeId\n} from \"./entity-helpers\";\nimport { sanitizeAndConvertDates, serializeDataToServer } from \"../data-transformer\";\nimport { RelationService } from \"./RelationService\";\nimport { EntityFetchService } from \"./EntityFetchService\";\nimport { DrizzleClient } from \"../interfaces\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { logger } from \"@rebasepro/server-core\";\nimport { extractPgError, extractCauseMessage, pgErrorToFriendlyMessage } from \"../utils/pg-error-utils\";\n\n/**\n * Service for handling all entity write operations.\n * Handles saving, deleting, and updating entities.\n */\nexport class EntityPersistService {\n private relationService: RelationService;\n private fetchService: EntityFetchService;\n\n constructor(private db: DrizzleClient, private registry: PostgresCollectionRegistry) {\n this.relationService = new RelationService(db, registry);\n this.fetchService = new EntityFetchService(db, registry);\n }\n\n\n /**\n * Delete an entity by ID\n */\n async deleteEntity(collectionPath: string, entityId: string | number, _databaseId?: string): Promise<void> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const idInfo = idInfoArray[0];\n const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;\n\n if (!idField) {\n throw new Error(`ID field '${idInfo.fieldName}' not found in table for collection '${collectionPath}'`);\n }\n\n const parsedIdObj = parseIdValues(entityId, idInfoArray);\n const parsedId = parsedIdObj[idInfo.fieldName];\n\n await this.db\n .delete(table)\n .where(eq(idField, parsedId));\n }\n\n /**\n * Delete all entities from a collection\n */\n async deleteAll(collectionPath: string, _databaseId?: string): Promise<void> {\n const collection = getCollectionByPath(collectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n await this.db.delete(table);\n }\n\n /**\n * Save an entity (create or update)\n */\n async saveEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n values: Partial<M>,\n entityId?: string | number,\n databaseId?: string\n ): Promise<Entity<M>> {\n // If saving under a nested relation path, resolve the parent and inject FK\n let effectiveCollectionPath = collectionPath;\n const effectiveValues: Partial<M> = { ...values };\n let junctionTableInfo: { parentCollection: EntityCollection; parentId: string | number; relation: Relation; relationKey: string; } | undefined;\n\n if (collectionPath.includes(\"/\")) {\n const segments = collectionPath.split(\"/\").filter(Boolean);\n if (segments.length >= 3 && segments.length % 2 === 1) {\n const rootSegment = segments[0];\n let currentCollection = getCollectionByPath(rootSegment, this.registry);\n let currentEntityId: string | number = segments[1];\n\n for (let i = 2; i < segments.length; i += 2) {\n const relationKey = segments[i];\n const resolvedRelations = resolveCollectionRelations(currentCollection);\n const relation = findRelation(resolvedRelations, relationKey);\n\n if (!relation) {\n const available = Object.keys(resolvedRelations).join(\", \") || \"(none)\";\n throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'. Available relations: [${available}]`);\n }\n\n if (i === segments.length - 1) {\n const targetCollection = relation.target();\n effectiveCollectionPath = targetCollection.slug;\n\n // Handle many-to-many with junction table\n if (relation.cardinality === \"many\" && relation.through) {\n const parentIdInfoArray = getPrimaryKeys(currentCollection, this.registry);\n const parentIdInfo = parentIdInfoArray[0];\n const parsedParentIdObj = parseIdValues(currentEntityId, parentIdInfoArray);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n junctionTableInfo = {\n parentCollection: currentCollection,\n parentId: parsedParentId,\n relation: relation,\n relationKey: relationKey\n };\n break;\n }\n\n // Find the FK column that should store the parent ID\n let targetColumnName: string;\n\n if (relation.localKey) {\n targetColumnName = relation.localKey;\n } else if (relation.foreignKeyOnTarget) {\n targetColumnName = relation.foreignKeyOnTarget;\n } else if (relation.joinPath && relation.joinPath.length === 1) {\n const targetTableName = getTableName(targetCollection);\n const relevantJoinStep = relation.joinPath.find(joinStep => joinStep.table === targetTableName);\n\n if (relevantJoinStep) {\n const targetColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(relevantJoinStep.on.to);\n targetColumnName = targetColumnNames[0];\n } else {\n logger.warn(`Could not find specific join step for target table ${targetTableName} in relation '${relationKey}'.`);\n const targetColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(relation.joinPath[0].on.to);\n targetColumnName = targetColumnNames[0];\n }\n } else if (relation.joinPath && relation.joinPath.length > 1) {\n // For multi-hop relations (like many-to-many through a junction table),\n // there is no direct foreign key on the target table pointing to the parent.\n // The relationship is managed via the junction table.\n // We shouldn't inject the parent ID directly into the target entity payload.\n break;\n } else {\n throw new Error(`Relation '${relationKey}' lacks configuration for path-based saving.`);\n }\n\n const parentIdInfoArray = getPrimaryKeys(currentCollection, this.registry);\n const parentIdInfo = parentIdInfoArray[0];\n const parsedParentIdObj = parseIdValues(currentEntityId, parentIdInfoArray);\n const parsedParentId = parsedParentIdObj[parentIdInfo.fieldName];\n\n const existingValue = (effectiveValues as Record<string, unknown>)[targetColumnName];\n if (existingValue !== undefined && existingValue !== null && existingValue !== parsedParentId) {\n logger.warn(`Overriding provided value '${existingValue}' for FK '${targetColumnName}' with path parent id '${parsedParentId}'.`);\n }\n (effectiveValues as Record<string, unknown>)[targetColumnName] = parsedParentId;\n break;\n } else {\n const nextEntityId = segments[i + 1];\n currentCollection = relation.target();\n currentEntityId = nextEntityId;\n }\n }\n }\n }\n\n const collection = getCollectionByPath(effectiveCollectionPath, this.registry);\n const table = getTableForCollection(collection, this.registry);\n const idInfoArray = getPrimaryKeys(collection, this.registry);\n const primaryKeyFields = idInfoArray.map(info => info.fieldName);\n\n // Build an object mapping required for dynamic returning\n const returningKeys: Record<string, AnyPgColumn> = {};\n idInfoArray.forEach(info => {\n const field = table[info.fieldName as keyof typeof table] as AnyPgColumn;\n if (!field) throw new Error(`Primary key field '${info.fieldName}' not found in table for collection '${effectiveCollectionPath}'`);\n returningKeys[info.fieldName] = field;\n });\n\n // Separate relations that require special handling\n const relationValues: Record<string, unknown> = {};\n const otherValues: Partial<M> = { ...effectiveValues };\n const resolvedRelations = resolveCollectionRelations(collection);\n\n for (const key in resolvedRelations) {\n const relation = resolvedRelations[key];\n if (relation && relation.cardinality === \"many\") {\n if (Object.prototype.hasOwnProperty.call(otherValues, key)) {\n relationValues[key] = otherValues[key as keyof M];\n delete otherValues[key as keyof M];\n }\n }\n }\n\n // Transform relations to IDs, then sanitize\n const serializedResult = serializeDataToServer(otherValues as M, collection.properties as Properties, collection, this.registry);\n\n // Extract relation updates from the typed result\n const inverseRelationUpdates = serializedResult.inverseRelationUpdates;\n const joinPathRelationUpdates = serializedResult.joinPathRelationUpdates;\n\n const entityData = sanitizeAndConvertDates(serializedResult.scalarData);\n\n let savedId: string | number;\n try {\n savedId = await this.db.transaction(async (tx) => {\n let currentId: string | number;\n\n if (entityId) {\n // Update existing entity\n currentId = entityId; // `entityId` is already the formatted composite or singular string\n const idValues = parseIdValues(entityId, idInfoArray);\n\n // Apply joinPath one-to-one relation updates BEFORE the main UPDATE.\n // This ensures parentSourceCol reads the pre-update FK value, preventing\n // stale joinPath values from corrupting related entities when an\n // intermediate FK (e.g., author_id) changes in the same save.\n // Example: changing author A→B with stale profile P1 (A's):\n // reads old author_id=A → clears P1.author_id → re-sets P1.author_id=A (no-op).\n if (joinPathRelationUpdates.length > 0) {\n await this.relationService.updateJoinPathOneToOneRelations(tx, collection, currentId, joinPathRelationUpdates);\n }\n\n // Only issue an UPDATE if there are scalar columns to set.\n // When the payload contains only relation data, entityData is\n // empty after relation stripping and Drizzle throws \"No values to set\".\n const scalarKeys = Object.keys(entityData as Record<string, unknown>);\n if (scalarKeys.length > 0) {\n const updateQuery = tx.update(table).set(entityData as Record<string, unknown>);\n const conditions = [];\n for (const info of idInfoArray) {\n const field = table[info.fieldName as keyof typeof table] as AnyPgColumn;\n conditions.push(eq(field, idValues[info.fieldName]));\n }\n\n await updateQuery.where(and(...conditions));\n }\n } else {\n const dataForInsert = { ...(entityData as Record<string, unknown>) };\n\n // Strip empty primary keys so the database defaults (e.g. uuid_gen(), auto-increment) can trigger\n for (const info of idInfoArray) {\n if (dataForInsert[info.fieldName] === \"\" || dataForInsert[info.fieldName] === null || dataForInsert[info.fieldName] === undefined) {\n delete dataForInsert[info.fieldName];\n }\n }\n\n const result = await tx\n .insert(table)\n .values(dataForInsert)\n .returning(returningKeys);\n\n const resultRow = result[0];\n currentId = buildCompositeId(resultRow, idInfoArray);\n\n // For inserts, apply joinPath after since the parent row didn't exist before\n if (joinPathRelationUpdates.length > 0) {\n await this.relationService.updateJoinPathOneToOneRelations(tx, collection, currentId, joinPathRelationUpdates);\n }\n }\n\n // Handle inverse relation updates\n if (inverseRelationUpdates.length > 0) {\n await this.relationService.updateInverseRelations(tx, collection, currentId, inverseRelationUpdates);\n }\n\n // Update many-to-many relations\n if (Object.keys(relationValues).length > 0) {\n await this.relationService.updateRelationsUsingJoins(tx, collection, currentId, relationValues);\n }\n\n // Handle junction table creation for many-to-many path-based saves\n if (junctionTableInfo && !entityId) {\n await this.relationService.handleJunctionTableCreation(tx, currentId, junctionTableInfo);\n }\n\n return currentId;\n });\n } catch (error: unknown) {\n throw this.toUserFriendlyError(error, collection.slug);\n }\n\n // Fetch the updated/created entity to return with proper relation objects\n const finalEntity = await this.fetchService.fetchEntity<M>(collection.slug, savedId, databaseId);\n if (!finalEntity) throw new Error(\"Could not fetch entity after save.\");\n return finalEntity;\n }\n\n /**\n * Get the RelationService instance for external use\n */\n getRelationService(): RelationService {\n return this.relationService;\n }\n\n /**\n * Get the FetchService instance for external use\n */\n getFetchService(): EntityFetchService {\n return this.fetchService;\n }\n\n /**\n * Translate raw PostgreSQL / Drizzle errors into user-friendly messages.\n */\n private toUserFriendlyError(error: unknown, collectionSlug: string): Error {\n const pgError = extractPgError(error);\n\n if (pgError) {\n const { message } = pgErrorToFriendlyMessage(pgError, collectionSlug);\n return new Error(message);\n }\n\n // No PG error found — try to extract a useful message from the\n // Drizzle wrapper instead of leaking the raw SQL query + params.\n const causeMessage = extractCauseMessage(error);\n if (causeMessage) {\n return new Error(`Database error in \"${collectionSlug}\": ${causeMessage}`);\n }\n\n // Last resort: generic message, never leak raw SQL\n if (error instanceof Error && error.message.startsWith(\"Failed query:\")) {\n return new Error(`Failed to save entity in \"${collectionSlug}\". Check server logs for details.`);\n }\n return new Error(`Database error in \"${collectionSlug}\": ${String(error)}`);\n }\n}\n","// import { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { Entity, FilterValues } from \"@rebasepro/types\";\nimport type { VectorSearchParams } from \"@rebasepro/types\";\nimport { EntityFetchService } from \"./EntityFetchService\";\nimport { EntityPersistService } from \"./EntityPersistService\";\nimport { RelationService } from \"./RelationService\";\nimport { EntityRepository, FetchCollectionOptions, SearchOptions, CountOptions, DrizzleClient } from \"../interfaces\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\n\n// Re-export data transformer functions for external use\nexport { sanitizeAndConvertDates, serializeDataToServer, parseDataFromServer } from \"../data-transformer\";\n\n// Re-export service classes for direct use\nexport { EntityFetchService } from \"./EntityFetchService\";\nexport { EntityPersistService } from \"./EntityPersistService\";\nexport { RelationService } from \"./RelationService\";\n\n// Re-export interfaces\nexport * from \"../interfaces\";\n\n/**\n * EntityService - Facade for entity operations.\n *\n * This class provides a unified API for entity CRUD operations by delegating\n * to specialized services:\n * - EntityFetchService: Read operations (fetch, search, count)\n * - EntityPersistService: Write operations (save, delete)\n * - RelationService: Relation operations (fetch related, update relations)\n *\n * Implements the EntityRepository interface for database abstraction.\n */\nexport class EntityService implements EntityRepository {\n private fetchService: EntityFetchService;\n private persistService: EntityPersistService;\n\n constructor(private db: DrizzleClient, private registry: PostgresCollectionRegistry) {\n this.fetchService = new EntityFetchService(db, registry);\n this.persistService = new EntityPersistService(db, registry);\n }\n\n // =============================================================\n // READ OPERATIONS - Delegated to EntityFetchService\n // =============================================================\n\n /**\n * Fetch a single entity by ID\n */\n async fetchEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n entityId: string | number,\n databaseId?: string\n ): Promise<Entity<M> | undefined> {\n return this.fetchService.fetchEntity<M>(collectionPath, entityId, databaseId);\n }\n\n /**\n * Fetch a collection of entities with optional filtering, ordering, and pagination\n */\n async fetchCollection<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n vectorSearch?: VectorSearchParams;\n } = {}\n ): Promise<Entity<M>[]> {\n return this.fetchService.fetchCollection<M>(collectionPath, options);\n }\n\n /**\n * Search entities by text\n */\n async searchEntities<M extends Record<string, unknown>>(\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 } = {}\n ): Promise<Entity<M>[]> {\n return this.fetchService.searchEntities<M>(collectionPath, searchString, options);\n }\n\n /**\n * Count entities in a collection\n */\n async countEntities<M extends Record<string, unknown>>(\n collectionPath: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<number> {\n return this.fetchService.countEntities<M>(collectionPath, options);\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: unknown,\n excludeEntityId?: string,\n databaseId?: string\n ): Promise<boolean> {\n return this.fetchService.checkUniqueField(collectionPath, fieldName, value, excludeEntityId, databaseId);\n }\n\n /**\n * Fetch entities related to a parent entity\n */\n async fetchRelatedEntities<M extends Record<string, unknown>>(\n parentCollectionPath: string,\n parentEntityId: string | number,\n relationKey: string,\n options: {\n filter?: FilterValues<Extract<keyof M, string>>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n startAfter?: Record<string, unknown>;\n searchString?: string;\n databaseId?: string;\n } = {}\n ): Promise<Entity<M>[]> {\n return this.fetchService.getRelationService().fetchRelatedEntities<M>(\n parentCollectionPath,\n parentEntityId,\n relationKey,\n options\n );\n }\n\n // =============================================================\n // WRITE OPERATIONS - Delegated to EntityPersistService\n // =============================================================\n\n /**\n * Save an entity (create or update)\n */\n async saveEntity<M extends Record<string, unknown>>(\n collectionPath: string,\n values: Partial<M>,\n entityId?: string | number,\n databaseId?: string\n ): Promise<Entity<M>> {\n return this.persistService.saveEntity<M>(collectionPath, values, entityId, databaseId);\n }\n\n /**\n * Delete an entity by ID\n */\n async deleteEntity(\n collectionPath: string,\n entityId: string | number,\n databaseId?: string\n ): Promise<void> {\n return this.persistService.deleteEntity(collectionPath, entityId, databaseId);\n }\n\n /**\n * Delete all entities from a collection\n */\n async deleteAll(collectionPath: string, databaseId?: string): Promise<void> {\n return this.persistService.deleteAll(collectionPath, databaseId);\n }\n\n\n /**\n * Execute raw SQL\n */\n async executeSql(sqlText: string): Promise<Record<string, unknown>[]> {\n if (process.env.NODE_ENV !== \"production\") {\n console.debug(\"Executing raw SQL:\", sqlText);\n }\n const { sql } = await import(\"drizzle-orm\");\n const result = await this.db.execute(sql.raw(sqlText));\n const rows = result.rows;\n if (process.env.NODE_ENV !== \"production\") {\n console.debug(`SQL executed successfully. Returned ${Array.isArray(rows) ? rows.length : \"non-array\"} rows.`);\n }\n return rows as Record<string, unknown>[];\n }\n\n // =============================================================\n // SERVICE ACCESSORS\n // =============================================================\n\n /**\n * Get the underlying EntityFetchService for advanced use\n */\n getFetchService(): EntityFetchService {\n return this.fetchService;\n }\n\n /**\n * Get the underlying EntityPersistService for advanced use\n */\n getPersistService(): EntityPersistService {\n return this.persistService;\n }\n\n /**\n * Get the underlying RelationService for advanced use\n */\n getRelationService(): RelationService {\n return this.fetchService.getRelationService();\n }\n}\n","/**\n * BranchService\n *\n * Manages database branching by creating/deleting PostgreSQL databases\n * using `CREATE DATABASE ... TEMPLATE`. Branch metadata is stored in the\n * `rebase.branches` table in the default (main) database, following the\n * same `rebase` schema convention used by entity_history, auth, etc.\n */\n\nimport { sql } from \"drizzle-orm\";\nimport { BranchInfo } from \"@rebasepro/types\";\nimport { DrizzleClient } from \"../interfaces\";\nimport { DatabasePoolManager } from \"../databasePoolManager\";\n\n/** Internal prefix applied to branch database names to avoid collisions. */\nconst BRANCH_DB_PREFIX = \"rb_\";\n\n/** Fully-qualified metadata table in the rebase schema. */\nconst BRANCHES_TABLE = \"rebase.branches\";\n\n/**\n * Validate that a user-provided identifier only contains safe characters.\n * Throws if the value contains characters outside [a-zA-Z0-9_-].\n */\nfunction validateIdentifier(value: string, label: string): void {\n if (!/^[a-zA-Z0-9_-]+$/.test(value)) {\n throw new Error(`Invalid ${label}: only letters, digits, underscores, and hyphens are allowed.`);\n }\n}\n\n/**\n * Sanitize a user-provided branch name to a safe PostgreSQL identifier.\n * Only allows alphanumeric characters and underscores.\n */\nfunction sanitizeBranchName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, \"\");\n}\n\n/**\n * Convert a user-facing branch name to the actual PostgreSQL database name.\n */\nfunction toBranchDbName(name: string): string {\n const sanitized = sanitizeBranchName(name);\n if (!sanitized) throw new Error(\"Branch name must contain at least one alphanumeric character.\");\n return `${BRANCH_DB_PREFIX}${sanitized}`;\n}\n\nexport class BranchService {\n constructor(\n private db: DrizzleClient,\n private poolManager: DatabasePoolManager\n ) {}\n\n /**\n * Ensure the `rebase.branches` metadata table exists in the default database.\n * Idempotent — safe to call on every startup.\n */\n async ensureBranchMetadataTable(): Promise<void> {\n // Create the rebase schema (idempotent — may already exist from auth/history init)\n await this.db.execute(sql`CREATE SCHEMA IF NOT EXISTS rebase`);\n\n await this.db.execute(sql.raw(`\n CREATE TABLE IF NOT EXISTS ${BRANCHES_TABLE} (\n name TEXT PRIMARY KEY,\n db_name TEXT NOT NULL UNIQUE,\n parent_db TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n metadata JSONB DEFAULT '{}'\n );\n `));\n }\n\n /**\n * Create a new branch database by templating the source database.\n *\n * Uses `CREATE DATABASE ... TEMPLATE` for an instant, full-fidelity copy\n * of both schema and data.\n *\n * @param name User-facing branch name (e.g., \"feature_auth\")\n * @param options.source Source database to clone; defaults to the main database.\n */\n async createBranch(name: string, options?: { source?: string }): Promise<BranchInfo> {\n if (options?.source) {\n validateIdentifier(options.source, \"source database name\");\n }\n\n const dbName = toBranchDbName(name);\n const sanitizedName = sanitizeBranchName(name);\n const sourceDb = options?.source || this.poolManager.defaultDatabaseName;\n\n // Check if branch already exists\n const existing = await this.db.execute(\n sql`SELECT name FROM rebase.branches WHERE name = ${sanitizedName} OR db_name = ${dbName}`\n );\n if ((existing.rows as unknown[]).length > 0) {\n throw new Error(`Branch \"${sanitizedName}\" already exists.`);\n }\n\n // Disconnect any idle pools to the source DB so TEMPLATE works.\n // CREATE DATABASE ... TEMPLATE requires no other connections to the template.\n await this.poolManager.disconnectDatabase(sourceDb);\n\n // Create the database using the source as a template.\n // Note: Identifiers must be double-quoted, not parameterized.\n const safeDbName = dbName.replace(/\"/g, '\"\"');\n const safeSourceDb = sourceDb.replace(/\"/g, '\"\"');\n try {\n await this.db.execute(\n sql.raw(`CREATE DATABASE \"${safeDbName}\" TEMPLATE \"${safeSourceDb}\"`)\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"already exists\")) {\n throw new Error(`Database \"${dbName}\" already exists on the server. Choose a different branch name.`);\n }\n // If template fails due to active connections, provide a helpful error\n if (msg.includes(\"being accessed by other users\")) {\n throw new Error(\n `Cannot create branch: the source database \"${sourceDb}\" has active connections. ` +\n \"Close other clients or connections and try again.\"\n );\n }\n throw err;\n }\n\n // Record metadata in the default database\n const now = new Date();\n await this.db.execute(\n sql`INSERT INTO rebase.branches (name, db_name, parent_db, created_at) \n VALUES (${sanitizedName}, ${dbName}, ${sourceDb}, ${now.toISOString()})`\n );\n\n return {\n name: sanitizedName,\n parentDatabase: sourceDb,\n createdAt: now\n };\n }\n\n /**\n * Delete a branch database and remove its metadata.\n * Cannot delete the main/default database.\n */\n async deleteBranch(name: string): Promise<void> {\n const sanitizedName = sanitizeBranchName(name);\n const dbName = toBranchDbName(name);\n\n // Safety: never delete the default database\n if (dbName === this.poolManager.defaultDatabaseName) {\n throw new Error(\"Cannot delete the main database.\");\n }\n\n // Verify the branch exists in our metadata\n const existing = await this.db.execute(\n sql`SELECT db_name FROM rebase.branches WHERE name = ${sanitizedName}`\n );\n if ((existing.rows as unknown[]).length === 0) {\n throw new Error(`Branch \"${sanitizedName}\" not found.`);\n }\n\n // Disconnect any pools to this branch before dropping\n await this.poolManager.disconnectDatabase(dbName);\n\n // Drop the database\n const safeDbName = dbName.replace(/\"/g, '\"\"');\n try {\n await this.db.execute(sql.raw(`DROP DATABASE \"${safeDbName}\"`));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"being accessed by other users\")) {\n throw new Error(\n `Cannot delete branch \"${sanitizedName}\": the database has active connections. ` +\n \"Close other clients and try again.\"\n );\n }\n throw err;\n }\n\n // Remove metadata\n await this.db.execute(\n sql`DELETE FROM rebase.branches WHERE name = ${sanitizedName}`\n );\n }\n\n /**\n * List all branches recorded in the metadata table.\n * Optionally fetches database sizes from pg_database.\n */\n async listBranches(): Promise<BranchInfo[]> {\n const result = await this.db.execute(sql.raw(`\n SELECT \n b.name,\n b.parent_db,\n b.created_at,\n pg_database_size(b.db_name) as size_bytes\n FROM ${BRANCHES_TABLE} b\n JOIN pg_database d ON d.datname = b.db_name\n ORDER BY b.created_at DESC\n `));\n\n return (result.rows as Record<string, unknown>[]).map((row) => ({\n name: row.name as string,\n parentDatabase: row.parent_db as string,\n createdAt: new Date(row.created_at as string),\n sizeBytes: row.size_bytes != null ? Number(row.size_bytes) : undefined\n }));\n }\n\n /**\n * Get info about a specific branch.\n */\n async getBranchInfo(name: string): Promise<BranchInfo | undefined> {\n const sanitizedName = sanitizeBranchName(name);\n\n const result = await this.db.execute(sql`\n SELECT \n b.name,\n b.parent_db,\n b.created_at\n FROM rebase.branches b\n WHERE b.name = ${sanitizedName}\n `);\n\n const rows = result.rows as Record<string, unknown>[];\n if (rows.length === 0) return undefined;\n\n const row = rows[0];\n\n // Attempt to get size — may fail if the DB was externally dropped\n let sizeBytes: number | undefined;\n try {\n const dbName = toBranchDbName(sanitizedName);\n const sizeResult = await this.db.execute(\n sql`SELECT pg_database_size(${dbName}) as size_bytes`\n );\n const sizeRows = sizeResult.rows as Record<string, unknown>[];\n if (sizeRows.length > 0 && sizeRows[0].size_bytes != null) {\n sizeBytes = Number(sizeRows[0].size_bytes);\n }\n } catch {\n // Database might not exist anymore\n }\n\n return {\n name: row.name as string,\n parentDatabase: row.parent_db as string,\n createdAt: new Date(row.created_at as string),\n sizeBytes\n };\n }\n}\n","import { EntityService } from \"./services/entityService\";\nimport { BranchService } from \"./services/BranchService\";\nimport { RealtimeService } from \"./services/realtimeService\";\nimport { DatabasePoolManager } from \"./databasePoolManager\";\nimport { DrizzleClient } from \"./interfaces\";\nimport {\n DatabaseAdmin,\n DataDriver,\n DeleteEntityProps,\n Entity,\n EntityCollection,\n FetchCollectionProps,\n FetchEntityProps,\n ListenCollectionProps,\n ListenEntityProps,\n RebaseCallContext,\n RebaseClient,\n RebaseData,\n RestFetchService,\n SaveEntityProps,\n TableColumnInfo,\n TableForeignKeyInfo,\n TableJunctionInfo,\n TableMetadata,\n TablePolicyInfo,\n User\n} from \"@rebasepro/types\";\nimport { sql as drizzleSql } from \"drizzle-orm\";\nimport { buildPropertyCallbacks, buildRebaseData, updateDateAutoValues } from \"@rebasepro/common\";\nimport { PostgresCollectionRegistry } from \"./collections/PostgresCollectionRegistry\";\nimport { HistoryService } from \"./history/HistoryService\";\nimport { mergeDeep } from \"@rebasepro/utils\";\nimport { logger } from \"@rebasepro/server-core\";\n\nexport class PostgresBackendDriver implements DataDriver {\n key = \"postgres\";\n initialised = true;\n\n public entityService: EntityService;\n public realtimeService: RealtimeService;\n public historyService?: HistoryService;\n public branchService?: BranchService;\n public user?: User;\n public data: RebaseData;\n public client?: RebaseClient;\n\n /**\n * When true, realtime notifications are deferred until after the\n * wrapping transaction commits. Set by `withAuth` → `withTransaction`.\n */\n _deferNotifications = false;\n _pendingNotifications: Array<{\n path: string;\n entityId: string;\n entity: Entity | null;\n databaseId?: string;\n }> = [];\n\n constructor(\n public db: DrizzleClient,\n realtimeService: RealtimeService,\n public readonly registry: PostgresCollectionRegistry,\n user?: User,\n public poolManager?: DatabasePoolManager,\n historyService?: HistoryService\n ) {\n this.entityService = new EntityService(db, registry);\n this.realtimeService = realtimeService;\n this.historyService = historyService;\n this.user = user;\n this.data = buildRebaseData(this);\n\n // Initialize BranchService when adminConnectionString is configured\n if (poolManager) {\n this.branchService = new BranchService(db, poolManager);\n }\n\n }\n\n /**\n * Typed admin capabilities (SQLAdmin + SchemaAdmin + BranchAdmin).\n * Implemented as a getter so method references are resolved at call-time,\n * allowing test spies applied after construction to take effect.\n */\n get admin(): DatabaseAdmin {\n return {\n executeSql: (...args: Parameters<NonNullable<DatabaseAdmin[\"executeSql\"]>>) => this.executeSql(...args),\n fetchAvailableDatabases: () => this.fetchAvailableDatabases(),\n fetchAvailableRoles: () => this.fetchAvailableRoles(),\n fetchCurrentDatabase: () => this.fetchCurrentDatabase(),\n fetchUnmappedTables: (...args: Parameters<NonNullable<DatabaseAdmin[\"fetchUnmappedTables\"]>>) => this.fetchUnmappedTables(...args),\n fetchTableMetadata: (...args: Parameters<NonNullable<DatabaseAdmin[\"fetchTableMetadata\"]>>) => this.fetchTableMetadata(...args),\n // Branch operations (only available when poolManager is configured)\n ...(this.branchService ? {\n createBranch: this.branchService.createBranch.bind(this.branchService),\n deleteBranch: this.branchService.deleteBranch.bind(this.branchService),\n listBranches: this.branchService.listBranches.bind(this.branchService),\n getBranchInfo: this.branchService.getBranchInfo.bind(this.branchService)\n } : {})\n };\n }\n\n /**\n * REST-optimised fetch service (include-aware eager-loading).\n * Delegates to the underlying EntityFetchService which already\n * implements the matching method signatures.\n */\n get restFetchService() {\n return this.entityService.getFetchService();\n }\n\n private buildCallContext(): RebaseCallContext {\n return {\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\n private resolveCollectionCallbacks<M extends Record<string, unknown>>(collection: EntityCollection<M> | undefined, path: string) {\n if (!collection && !path) return {\n collection: undefined,\n callbacks: undefined,\n propertyCallbacks: undefined\n };\n const registryCollection = this.registry?.getCollectionByPath(path);\n const resolvedCollection = registryCollection\n ? {\n ...collection,\n ...registryCollection\n } as EntityCollection<M>\n : collection as EntityCollection<M>;\n\n const callbacks = resolvedCollection?.callbacks;\n const properties = resolvedCollection?.properties;\n let propertyCallbacks;\n if (properties) {\n propertyCallbacks = buildPropertyCallbacks(properties);\n }\n return {\n collection: resolvedCollection,\n callbacks,\n propertyCallbacks\n };\n }\n\n async fetchCollection<M extends Record<string, unknown>>({\n path,\n collection,\n filter,\n limit,\n offset,\n startAfter,\n orderBy,\n searchString,\n order,\n vectorSearch\n }: FetchCollectionProps<M>): Promise<Entity<M>[]> {\n\n const entities = await this.entityService.fetchCollection<M>(path, {\n filter,\n orderBy,\n order,\n limit,\n offset,\n startAfter: startAfter as Record<string, unknown> | undefined,\n databaseId: collection?.databaseId,\n searchString,\n vectorSearch\n });\n\n const {\n collection: resolvedCollection,\n callbacks,\n propertyCallbacks\n } = this.resolveCollectionCallbacks(collection, path);\n\n if (callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = this.buildCallContext();\n return Promise.all(entities.map(async (entity) => {\n let fetched = entity;\n if (callbacks?.afterRead) {\n fetched = await callbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity: fetched,\n context: contextForCallback\n }) ?? fetched;\n }\n if (propertyCallbacks?.afterRead) {\n fetched = await propertyCallbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity: fetched,\n context: contextForCallback\n }) as Entity<M> ?? fetched;\n }\n return fetched;\n }));\n }\n\n return entities;\n }\n\n listenCollection<M extends Record<string, unknown>>({\n path,\n collection,\n filter,\n limit,\n offset,\n startAfter,\n orderBy,\n searchString,\n order,\n onUpdate,\n onError\n }: ListenCollectionProps<M>): () => void {\n\n const subscriptionId = this.generateSubscriptionId();\n\n // Type-adapter wrapper: RealtimeService expects a union callback signature\n const callbackWrapper = (entities: Entity<M>[]) => {\n onUpdate(entities);\n };\n\n // Store the subscription in RealtimeService properly using the new public method\n this.realtimeService.registerDataDriverSubscription(subscriptionId, {\n clientId: \"driver\",\n type: \"collection\" as const,\n path,\n collectionRequest: {\n filter,\n orderBy,\n order,\n limit,\n offset,\n startAfter: startAfter as Record<string, unknown> | undefined,\n databaseId: collection?.databaseId,\n searchString\n }\n });\n\n // Store the callback for this subscription\n this.realtimeService.addSubscriptionCallback(subscriptionId, callbackWrapper as (data: Entity | Entity[] | null) => void);\n\n // Send initial data immediately\n this.fetchCollection({\n path: path,\n collection,\n filter,\n limit,\n offset,\n startAfter,\n orderBy,\n searchString,\n order\n }).then(entities => {\n callbackWrapper(entities);\n }).catch(error => {\n if (onError) onError(error);\n });\n\n return () => {\n this.realtimeService.removeSubscriptionCallback(subscriptionId);\n this.realtimeService.subscriptions.delete(subscriptionId);\n };\n }\n\n async fetchEntity<M extends Record<string, unknown>>({\n path,\n entityId,\n databaseId,\n collection\n }: FetchEntityProps<M>): Promise<Entity<M> | undefined> {\n let entity = await this.entityService.fetchEntity<M>(\n path,\n entityId,\n databaseId || collection?.databaseId\n );\n\n const {\n collection: resolvedCollection,\n callbacks,\n propertyCallbacks\n } = this.resolveCollectionCallbacks(collection, path);\n\n if (entity && (callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n const contextForCallback = this.buildCallContext();\n if (callbacks?.afterRead) {\n entity = await callbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity,\n context: contextForCallback\n }) ?? entity;\n }\n if (propertyCallbacks?.afterRead) {\n entity = await propertyCallbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity,\n context: contextForCallback\n }) as Entity<M> ?? entity;\n }\n }\n\n return entity;\n }\n\n listenEntity<M extends Record<string, unknown>>({\n path,\n entityId,\n collection,\n onUpdate,\n onError\n }: ListenEntityProps<M>): () => void {\n\n const subscriptionId = this.generateSubscriptionId();\n const callbackWrapper = (entity: Entity<M> | null) => {\n if (entity)\n onUpdate(entity);\n };\n\n // Register the subscription with the RealtimeService\n this.realtimeService.registerDataDriverSubscription(subscriptionId, {\n clientId: \"driver\",\n type: \"entity\" as const,\n path,\n entityId\n });\n\n // Store the callback for this subscription\n this.realtimeService.addSubscriptionCallback(subscriptionId, callbackWrapper as (data: Entity | Entity[] | null) => void);\n\n // Fetch initial data\n this.fetchEntity({\n path,\n entityId,\n collection\n })\n .then(entity => {\n if (entity) onUpdate(entity);\n })\n .catch(error => {\n if (onError) onError(error as Error);\n });\n\n // Return the unsubscribe function\n return () => {\n this.realtimeService.removeSubscriptionCallback(subscriptionId);\n this.realtimeService.subscriptions.delete(subscriptionId);\n };\n }\n\n async saveEntity<M extends Record<string, unknown>>({\n path,\n entityId,\n values,\n collection,\n status\n }: SaveEntityProps<M>): Promise<Entity<M>> {\n\n const {\n collection: resolvedCollection,\n callbacks,\n propertyCallbacks\n } = this.resolveCollectionCallbacks(collection, path);\n\n let updatedValues = values;\n const contextForCallback = this.buildCallContext();\n\n // Fetch previous values for callbacks AND history recording\n let previousValuesForHistory: Partial<Entity<M>[\"values\"]> | undefined;\n if (status === \"existing\" && entityId) {\n const existing = await this.entityService.fetchEntity<M>(path, entityId, resolvedCollection?.databaseId);\n if (existing) {\n previousValuesForHistory = existing.values as Partial<Entity<M>[\"values\"]>;\n }\n }\n\n if (callbacks?.beforeSave || propertyCallbacks?.beforeSave) {\n if (callbacks?.beforeSave) {\n const result = await callbacks.beforeSave({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entityId,\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 EntityCollection<M>,\n path,\n entityId,\n values: updatedValues,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n if (result) updatedValues = mergeDeep(updatedValues, result);\n }\n\n }\n\n // Apply autoValue timestamps (on_create / on_update) at the application layer.\n // This handles updated_at fields for all writes that flow through the Rebase backend.\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 savedEntity = await this.entityService.saveEntity<M>(\n path,\n updatedValues,\n entityId,\n resolvedCollection?.databaseId\n );\n\n if (savedEntity && (callbacks?.afterRead || propertyCallbacks?.afterRead)) {\n if (callbacks?.afterRead) {\n savedEntity = await callbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity: savedEntity,\n context: contextForCallback\n }) ?? savedEntity;\n }\n if (propertyCallbacks?.afterRead) {\n savedEntity = await propertyCallbacks.afterRead({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entity: savedEntity,\n context: contextForCallback\n }) as Entity<M> ?? savedEntity;\n }\n }\n\n if (callbacks?.afterSave || propertyCallbacks?.afterSave) {\n if (callbacks?.afterSave) {\n await callbacks.afterSave({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entityId: savedEntity.id,\n values: savedEntity.values,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterSave) {\n await propertyCallbacks.afterSave({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entityId: savedEntity.id,\n values: savedEntity.values,\n previousValues: previousValuesForHistory,\n status,\n context: contextForCallback\n });\n }\n }\n\n // Record entity history (fire-and-forget, never blocks the save)\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n tableName: path,\n entityId: savedEntity.id.toString(),\n action: status === \"new\" ? \"create\" : \"update\",\n values: savedEntity.values as Record<string, unknown>,\n previousValues: previousValuesForHistory as Record<string, unknown> | undefined,\n updatedBy: this.user?.uid\n });\n }\n\n // Notify real-time subscribers (deferred if inside a transaction)\n if (this._deferNotifications) {\n this._pendingNotifications.push({\n path,\n entityId: savedEntity.id.toString(),\n entity: savedEntity,\n databaseId: resolvedCollection?.databaseId\n });\n } else {\n await this.realtimeService.notifyEntityUpdate(\n path,\n savedEntity.id.toString(),\n savedEntity,\n resolvedCollection?.databaseId\n );\n }\n\n return savedEntity;\n } catch (error) {\n if (callbacks?.afterSaveError || propertyCallbacks?.afterSaveError) {\n if (callbacks?.afterSaveError) {\n await callbacks.afterSaveError({\n collection: resolvedCollection as EntityCollection<M>,\n path,\n entityId: entityId || \"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 EntityCollection<M>,\n path,\n entityId: entityId || \"unknown\",\n values: updatedValues,\n previousValues: undefined,\n status,\n context: contextForCallback\n });\n }\n }\n throw error;\n }\n }\n\n async deleteEntity<M extends Record<string, unknown>>({\n entity,\n collection\n }: DeleteEntityProps<M>): Promise<void> {\n\n // Resolve from backend registry to restore callbacks lost during WebSocket serialization\n const {\n collection: resolvedCollection,\n callbacks,\n propertyCallbacks\n } = this.resolveCollectionCallbacks(collection, entity.path);\n\n const contextForCallback = this.buildCallContext();\n\n if (callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {\n let preventDefault = false;\n if (callbacks?.beforeDelete) {\n const result = await callbacks.beforeDelete({\n collection: resolvedCollection as EntityCollection<M>,\n path: entity.path,\n entityId: entity.id,\n entity,\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 EntityCollection<M>,\n path: entity.path,\n entityId: entity.id,\n entity,\n context: contextForCallback\n });\n if (result === false) {\n preventDefault = true;\n }\n }\n if (preventDefault) {\n return;\n }\n }\n\n await this.entityService.deleteEntity(\n entity.path,\n entity.id,\n entity.databaseId || resolvedCollection?.databaseId\n );\n\n if (callbacks?.afterDelete || propertyCallbacks?.afterDelete) {\n if (callbacks?.afterDelete) {\n await callbacks.afterDelete({\n collection: resolvedCollection as EntityCollection<M>,\n path: entity.path,\n entityId: entity.id,\n entity,\n context: contextForCallback\n });\n }\n if (propertyCallbacks?.afterDelete) {\n await propertyCallbacks.afterDelete({\n collection: resolvedCollection as EntityCollection<M>,\n path: entity.path,\n entityId: entity.id,\n entity,\n context: contextForCallback\n });\n }\n }\n\n // Record delete history (fire-and-forget)\n if (this.historyService && resolvedCollection?.history) {\n this.historyService.recordHistory({\n tableName: entity.path,\n entityId: entity.id.toString(),\n action: \"delete\",\n values: entity.values as Record<string, unknown>,\n updatedBy: this.user?.uid\n });\n }\n\n // Notify real-time subscribers (deferred if inside a transaction)\n if (this._deferNotifications) {\n this._pendingNotifications.push({\n path: entity.path,\n entityId: entity.id.toString(),\n entity: null,\n databaseId: entity.databaseId || resolvedCollection?.databaseId\n });\n } else {\n await this.realtimeService.notifyEntityUpdate(\n entity.path,\n entity.id.toString(),\n null,\n entity.databaseId || resolvedCollection?.databaseId\n );\n }\n\n }\n\n async deleteAll(path: string): Promise<void> {\n await this.entityService.deleteAll(path);\n // Notify real-time subscribers of bulk change\n await this.realtimeService.notifyEntityUpdate(path, \"*\", null);\n }\n\n async checkUniqueField(\n path: string,\n name: string,\n value: unknown,\n entityId?: string,\n collection?: EntityCollection\n ): Promise<boolean> {\n return this.entityService.checkUniqueField(\n path,\n name,\n value,\n entityId,\n collection?.databaseId\n );\n }\n\n async countEntities<M extends Record<string, unknown>>({\n path,\n collection,\n filter,\n searchString\n }: FetchCollectionProps<M>): Promise<number> {\n return this.entityService.countEntities(\n path,\n {\n filter,\n searchString\n }\n );\n }\n\n private getTargetDb(databaseName?: string): DrizzleClient {\n if (!databaseName || databaseName === this.poolManager?.defaultDatabaseName) {\n return this.db;\n }\n if (!this.poolManager) {\n throw new Error(\n \"Cross-database execution requires adminConnectionString to be configured in the backend.\"\n );\n }\n return this.poolManager.getDrizzle(databaseName);\n }\n\n async executeSql(sqlText: string, options?: {\n database?: string,\n role?: string\n }): Promise<Record<string, unknown>[]> {\n if (!options?.database && !options?.role) {\n return this.entityService.executeSql(sqlText);\n }\n\n const targetDb = this.getTargetDb(options?.database);\n\n try {\n // Determine if we actually need to switch roles.\n // Skip SET LOCAL ROLE when the requested role matches the current session role,\n // as it's a no-op that can fail on managed Postgres setups where the connection\n // user doesn't have permission to SET ROLE.\n let needsRoleSwitch = false;\n if (options?.role && process.env.DISABLE_DB_ROLE_SWITCHING !== \"true\") {\n try {\n const currentRoleResult = await targetDb.execute(drizzleSql.raw(\"SELECT current_user AS role\"));\n const currentRole = (currentRoleResult.rows?.[0] as Record<string, unknown>)?.role as string | undefined;\n needsRoleSwitch = !!currentRole && currentRole !== options.role;\n } catch {\n // If we can't determine the current role, attempt the switch anyway\n needsRoleSwitch = true;\n }\n }\n\n if (needsRoleSwitch && options?.role) {\n const safeRole = options.role.replace(/\"/g, \"\\\"\\\"\");\n return await targetDb.transaction(async (tx) => {\n await tx.execute(drizzleSql.raw(`SET LOCAL ROLE \"${safeRole}\"`));\n const result = await tx.execute(drizzleSql.raw(sqlText));\n return result.rows as Record<string, unknown>[];\n });\n }\n\n const result = await targetDb.execute(drizzleSql.raw(sqlText));\n return result.rows as Record<string, unknown>[];\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n // Provide a user-friendly message for connection/auth errors\n if (msg.includes(\"pg_hba.conf\") || msg.includes(\"no encryption\") || msg.includes(\"connection refused\")) {\n const dbName = options?.database || \"unknown\";\n throw new Error(`Cannot connect to database \"${dbName}\": the server rejected the connection. This database may require SSL or is not accessible from this host.`);\n }\n throw error;\n }\n }\n\n async fetchAvailableDatabases(): Promise<string[]> {\n // Exclude template databases, Cloud SQL internal databases, and the default 'postgres' system db\n const result = await this.executeSql(\n `SELECT datname FROM pg_database \n WHERE datistemplate = false \n AND datname NOT IN ('postgres', 'cloudsqladmin', '_cloudsqladmin')\n ORDER BY datname;`\n );\n const databases = result.map((r: Record<string, unknown>) => r.datname as string);\n // Ensure the current connected database is always first in the list\n const currentDb = this.poolManager?.defaultDatabaseName;\n if (currentDb && !databases.includes(currentDb)) {\n databases.unshift(currentDb);\n } else if (currentDb) {\n // Move it to the front\n const idx = databases.indexOf(currentDb);\n if (idx > 0) {\n databases.splice(idx, 1);\n databases.unshift(currentDb);\n }\n }\n return databases;\n }\n\n async fetchAvailableRoles(): Promise<string[]> {\n const result = await this.executeSql(\n \"SELECT rolname FROM pg_roles WHERE pg_has_role(current_user, rolname, 'member') ORDER BY rolname;\"\n );\n return result.map((r: Record<string, unknown>) => r.rolname as string);\n }\n\n async fetchCurrentDatabase(): Promise<string | undefined> {\n return this.poolManager?.defaultDatabaseName;\n }\n\n /**\n * Fetch public tables that are not yet mapped to a collection.\n * Excludes internal tables (_rebase_*, _auth_*, auth tables, etc.)\n * and junction/connection tables used for many-to-many relations.\n */\n async fetchUnmappedTables(mappedPaths?: string[]): Promise<string[]> {\n const result = await this.executeSql(`\n SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type = 'BASE TABLE'\n ORDER BY table_name;\n `);\n\n const internalPrefixes = [\"_rebase_\", \"_auth_\"];\n const internalExact = [\n \"users\", \"roles\", \"user_roles\", \"refresh_tokens\",\n \"password_reset_tokens\", \"email_verification_tokens\"\n ];\n\n const allTables = result\n .map((r: Record<string, unknown>) => r.table_name as string)\n .filter((name: string) => {\n if (internalPrefixes.some(prefix => name.startsWith(prefix))) return false;\n if (internalExact.includes(name)) return false;\n return true;\n });\n\n // Detect junction tables: tables where every column is part of a foreign key.\n // These are typically many-to-many connection tables and shouldn't be suggested.\n let junctionTables = new Set<string>();\n try {\n const junctionResult = await this.executeSql(`\n SELECT t.table_name\n FROM information_schema.tables t\n WHERE t.table_schema = 'public'\n AND t.table_type = 'BASE TABLE'\n AND NOT EXISTS (\n -- Find columns that are NOT part of any foreign key\n SELECT 1\n FROM information_schema.columns c\n WHERE c.table_schema = t.table_schema\n AND c.table_name = t.table_name\n AND c.column_name NOT IN (\n SELECT kcu.column_name\n FROM information_schema.key_column_usage kcu\n JOIN information_schema.table_constraints tc\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY'\n AND kcu.table_schema = t.table_schema\n AND kcu.table_name = t.table_name\n )\n );\n `);\n junctionTables = new Set(junctionResult.map((r: Record<string, unknown>) => r.table_name as string));\n } catch (e) {\n logger.warn(\"Could not detect junction tables\", { error: e });\n }\n\n const filteredTables = allTables.filter(name => !junctionTables.has(name));\n\n if (!mappedPaths || mappedPaths.length === 0) return filteredTables;\n\n const mappedSet = new Set(mappedPaths.map(p => p.toLowerCase()));\n return filteredTables.filter((name: string) => !mappedSet.has(name.toLowerCase()));\n }\n\n /**\n * Fetch metadata for a given table from information_schema (columns, policies, constraints).\n */\n async fetchTableMetadata(tableName: string): Promise<TableMetadata> {\n // Sanitize table name as defense-in-depth (parameterized below)\n const safeName = tableName.replace(/[^a-zA-Z0-9_]/g, \"\");\n\n // 1. Fetch Columns\n const result = await this.db.execute(drizzleSql`\n SELECT column_name, data_type, udt_name, is_nullable, column_default, character_maximum_length\n FROM information_schema.columns\n WHERE table_schema = 'public'\n AND table_name = ${safeName}\n ORDER BY ordinal_position\n `);\n const columns = result.rows as Record<string, unknown>[];\n\n // Also fetch enum values for any USER-DEFINED columns\n const enumColumns = columns.filter((c) => c.data_type === \"USER-DEFINED\");\n if (enumColumns.length > 0) {\n for (const col of enumColumns) {\n try {\n const enumResult = await this.db.execute(drizzleSql`\n SELECT e.enumlabel\n FROM pg_type t\n JOIN pg_enum e ON t.oid = e.enumtypid\n WHERE t.typname = ${col.udt_name as string}\n ORDER BY e.enumsortorder\n `);\n col.enum_values = (enumResult.rows as Record<string, unknown>[]).map(e => e.enumlabel);\n } catch {\n col.enum_values = [];\n }\n }\n }\n // SAFETY: Raw SQL result rows are typed as QueryResultRow[]; the query shape matches TableColumnInfo\n const typedColumns = columns as unknown as TableColumnInfo[];\n\n // 2. Fetch Foreign Keys\n const fkResult = await this.db.execute(drizzleSql`\n SELECT\n kcu.column_name as column_name,\n ccu.table_name AS foreign_table_name,\n ccu.column_name AS foreign_column_name\n FROM \n information_schema.table_constraints AS tc \n JOIN information_schema.key_column_usage AS kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n JOIN information_schema.constraint_column_usage AS ccu\n ON ccu.constraint_name = tc.constraint_name\n AND ccu.table_schema = tc.table_schema\n WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name = ${safeName};\n `);\n // SAFETY: Raw SQL result rows match TableForeignKeyInfo shape from the SELECT aliases\n const foreignKeys = fkResult.rows as TableForeignKeyInfo[];\n\n // 3. Fetch Junction Tables (Many-to-Many)\n // A simple junction table is one that has foreign keys to our table and other tables\n const junctionsResult = await this.db.execute(drizzleSql`\n SELECT \n tc1.table_name as junction_table_name,\n kcu1.column_name as source_column_name,\n ccu2.table_name as target_table_name,\n kcu2.column_name as target_column_name\n FROM information_schema.table_constraints tc1\n JOIN information_schema.key_column_usage kcu1 ON tc1.constraint_name = kcu1.constraint_name\n JOIN information_schema.constraint_column_usage ccu1 ON ccu1.constraint_name = tc1.constraint_name\n JOIN information_schema.table_constraints tc2 ON tc1.table_name = tc2.table_name AND tc2.constraint_type = 'FOREIGN KEY'\n JOIN information_schema.key_column_usage kcu2 ON tc2.constraint_name = kcu2.constraint_name\n JOIN information_schema.constraint_column_usage ccu2 ON ccu2.constraint_name = tc2.constraint_name\n WHERE tc1.constraint_type = 'FOREIGN KEY' \n AND ccu1.table_name = ${safeName}\n AND ccu2.table_name != ${safeName};\n `);\n // SAFETY: Raw SQL result rows match TableJunctionInfo shape from the SELECT aliases\n const junctions = junctionsResult.rows as TableJunctionInfo[];\n\n // 4. Fetch RLS Policies\n const policiesResult = await this.db.execute(drizzleSql`\n SELECT \n polname as policy_name, \n polcmd as cmd, \n polroles::regrole[]::text[] as roles, \n pg_get_expr(polqual, polrelid) as qual, \n pg_get_expr(polwithcheck, polrelid) as with_check\n FROM pg_policy\n WHERE polrelid = (SELECT oid FROM pg_class WHERE relname = ${safeName} AND relnamespace = 'public'::regnamespace);\n `);\n // SAFETY: Raw SQL result rows match TablePolicyInfo shape from the SELECT aliases\n const policies = policiesResult.rows as TablePolicyInfo[];\n\n return {\n columns: typedColumns,\n foreignKeys,\n junctions,\n policies\n };\n }\n\n private generateSubscriptionId(): string {\n return `sub_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Create a new delegate instance with authenticated context.\n * Starts a transaction and sets the current_user_id and current_user_roles\n * configuration parameters for PostgreSQL Row Level Security.\n */\n async withAuth(user: User): Promise<DataDriver> {\n return new AuthenticatedPostgresBackendDriver(this, user);\n }\n}\n\nexport class AuthenticatedPostgresBackendDriver implements DataDriver {\n key = \"postgres\";\n initialised = true;\n\n public user: User;\n public data: RebaseData;\n\n constructor(\n public delegate: PostgresBackendDriver,\n user: User\n ) {\n this.user = user;\n this.data = buildRebaseData(this);\n\n // Delegate admin ops to the base driver (no RLS wrapping for admin)\n this.admin = delegate.admin;\n }\n\n /**\n * Typed admin capabilities — delegates to the base driver.\n */\n admin: DatabaseAdmin;\n\n get restFetchService(): RestFetchService | undefined {\n if (!this.delegate.restFetchService) return undefined;\n return {\n fetchCollectionForRest: async (collectionPath, options, include) => {\n return this.withTransaction(async (delegate) => {\n return delegate.restFetchService.fetchCollectionForRest(collectionPath, options, include);\n }, { accessMode: \"read only\" });\n },\n fetchEntityForRest: async (collectionPath, entityId, include, databaseId) => {\n return this.withTransaction(async (delegate) => {\n return delegate.restFetchService.fetchEntityForRest(collectionPath, entityId, include, databaseId);\n }, { accessMode: \"read only\" });\n }\n };\n }\n\n private async withTransaction<T>(\n operation: (delegate: PostgresBackendDriver) => Promise<T>,\n options?: {\n accessMode?: \"read only\" | \"read write\";\n isolationLevel?: \"read uncommitted\" | \"read committed\" | \"repeatable read\" | \"serializable\"\n }\n ): Promise<T> {\n const pendingNotifications: PostgresBackendDriver[\"_pendingNotifications\"] = [];\n\n const result = await this.delegate.db.transaction(async (tx) => {\n let userId = this.user?.uid;\n if (!userId) {\n logger.warn(\"[DataDriver] User ID (uid) is missing for authenticated delegate. Using 'anonymous'. User object\", { detail: this.user });\n userId = \"anonymous\";\n }\n\n const userRoles = this.user?.roles ?? [];\n if (!this.user?.roles) {\n logger.warn(\"[DataDriver] User roles are missing for authenticated delegate. Using empty array. User object\", { detail: this.user });\n }\n const normalizedRoles = userRoles.map((r: unknown) =>\n typeof r === \"string\" ? r : (r as Record<string, unknown>)?.id ?? String(r)\n );\n const rolesString = normalizedRoles.join(\",\");\n\n await tx.execute(drizzleSql`\n SELECT \n set_config('app.user_id', ${userId}, true),\n set_config('app.user_roles', ${rolesString}, true),\n set_config('app.jwt', ${JSON.stringify({\n sub: userId,\n roles: userRoles\n })}, true)\n `);\n\n const txEntityService = new EntityService(tx, this.delegate.registry);\n const txDelegate = new PostgresBackendDriver(tx, this.delegate.realtimeService, this.delegate.registry, this.user, this.delegate.poolManager, this.delegate.historyService);\n\n txDelegate.entityService = txEntityService;\n txDelegate._deferNotifications = true;\n txDelegate._pendingNotifications = pendingNotifications;\n txDelegate.client = this.delegate.client;\n\n return await operation(txDelegate);\n }, options);\n\n for (const notification of pendingNotifications) {\n try {\n await this.delegate.realtimeService.notifyEntityUpdate(\n notification.path,\n notification.entityId,\n notification.entity,\n notification.databaseId\n );\n } catch (e) {\n logger.error(\"[DataDriver] Error flushing deferred notification\", { error: e });\n }\n }\n\n return result;\n }\n\n async fetchCollection<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<Entity<M>[]> {\n return this.withTransaction((delegate) => delegate.fetchCollection(props), { accessMode: \"read only\" });\n }\n\n /**\n * Injects the authenticated user's context into the most recently\n * registered realtime subscription so RLS-aware polling can apply.\n */\n private injectAuthContext(unsubscribe: () => void): () => void {\n const authContext = {\n userId: this.user?.uid || \"anonymous\",\n roles: this.user?.roles ?? []\n };\n const entries = Array.from(this.delegate.realtimeService.subscriptions.entries());\n const lastEntry = entries[entries.length - 1];\n const lastSub = lastEntry?.[1] as Record<string, unknown> | undefined;\n if (lastSub && lastSub.clientId === \"driver\") {\n lastSub.authContext = authContext;\n }\n return unsubscribe;\n }\n\n listenCollection<M extends Record<string, unknown>>(props: ListenCollectionProps<M>): () => void {\n return this.injectAuthContext(this.delegate.listenCollection(props));\n }\n\n async fetchEntity<M extends Record<string, unknown>>(props: FetchEntityProps<M>): Promise<Entity<M> | undefined> {\n return this.withTransaction((delegate) => delegate.fetchEntity(props), { accessMode: \"read only\" });\n }\n\n listenEntity<M extends Record<string, unknown>>(props: ListenEntityProps<M>): () => void {\n return this.injectAuthContext(this.delegate.listenEntity(props));\n }\n\n async saveEntity<M extends Record<string, unknown>>(props: SaveEntityProps<M>): Promise<Entity<M>> {\n return this.withTransaction((delegate) => delegate.saveEntity(props));\n }\n\n async deleteEntity<M extends Record<string, unknown>>(props: DeleteEntityProps<M>): Promise<void> {\n return this.withTransaction((delegate) => delegate.deleteEntity(props));\n }\n\n async deleteAll(path: string): Promise<void> {\n return this.withTransaction((delegate) => delegate.deleteAll(path));\n }\n\n async checkUniqueField(\n path: string,\n name: string,\n value: unknown,\n entityId?: string,\n collection?: EntityCollection\n ): Promise<boolean> {\n return this.withTransaction((delegate) => delegate.checkUniqueField(path, name, value, entityId, collection), { accessMode: \"read only\" });\n }\n\n async countEntities<M extends Record<string, unknown>>(props: FetchCollectionProps<M>): Promise<number> {\n return this.withTransaction((delegate) => delegate.countEntities(props), { accessMode: \"read only\" });\n }\n\n}\n","import { Pool } from \"pg\";\nimport { drizzle } from \"drizzle-orm/node-postgres\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { logger } from \"@rebasepro/server-core\";\n\nexport class DatabasePoolManager {\n private pools: Map<string, Pool> = new Map();\n private drizzleInstances: Map<string, NodePgDatabase> = new Map();\n public readonly defaultDatabaseName: string;\n private readonly rootConnectionString: string;\n\n constructor(adminConnectionString: string) {\n this.rootConnectionString = adminConnectionString;\n try {\n const url = new URL(adminConnectionString);\n this.defaultDatabaseName = url.pathname.slice(1);\n } catch (e) {\n throw new Error(`Invalid adminConnectionString provided: ${e}`);\n }\n }\n\n public getDrizzle(databaseName: string): NodePgDatabase<Record<string, never>> {\n const existing = this.drizzleInstances.get(databaseName);\n if (existing) {\n return existing;\n }\n\n const pool = this.getPool(databaseName);\n const db = drizzle(pool);\n this.drizzleInstances.set(databaseName, db);\n return db;\n }\n\n public getPool(databaseName: string): Pool {\n if (this.pools.has(databaseName)) {\n return this.pools.get(databaseName)!;\n }\n\n const url = new URL(this.rootConnectionString);\n url.pathname = `/${databaseName}`;\n\n const pool = new Pool({\n connectionString: url.toString(),\n max: 10, // Default sensible limit, can be tuned later\n idleTimeoutMillis: 10000, // Reduced from 30000 for aggressive cleanup\n allowExitOnIdle: true // Prevent idle clients from hanging the Node.js process\n });\n\n // Prevent idle client errors from crashing the Node.js process\n pool.on(\"error\", (err) => {\n logger.error(`[DatabasePoolManager] Unexpected error on idle client for db ${databaseName}`, { error: err });\n });\n\n this.pools.set(databaseName, pool);\n return pool;\n }\n\n /**\n * Disconnect and remove the pool for a specific database.\n * Required before `CREATE DATABASE ... TEMPLATE` or `DROP DATABASE`,\n * which need exclusive access to the target database.\n */\n public async disconnectDatabase(databaseName: string): Promise<void> {\n const pool = this.pools.get(databaseName);\n if (pool) {\n await pool.end();\n this.pools.delete(databaseName);\n this.drizzleInstances.delete(databaseName);\n }\n }\n\n /** Check if a pool exists for a given database name. */\n public hasPool(databaseName: string): boolean {\n return this.pools.has(databaseName);\n }\n\n public async shutdown(): Promise<void> {\n const promises = [];\n for (const [dbName, pool] of this.pools.entries()) {\n logger.info(`[DatabasePoolManager] Shutting down pool for ${dbName}`);\n promises.push(pool.end());\n }\n await Promise.all(promises);\n this.pools.clear();\n this.drizzleInstances.clear();\n }\n}\n","import { pgSchema, pgTable, varchar, uuid, timestamp, boolean, jsonb, text, unique } from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\n\n/**\n * Factory function to dynamically create the auth tables bound to the specified schema names.\n */\nexport function createAuthSchema(usersSchemaName = \"rebase\") {\n const usersSchema = usersSchemaName === \"public\" ? null : pgSchema(usersSchemaName);\n\n const tableCreator = (usersSchema ? usersSchema.table.bind(usersSchema) : pgTable) as typeof pgTable;\n const usersTableCreator = tableCreator;\n\n /**\n * Users table - stores both email/password and OAuth users\n */\n const users = usersTableCreator(\"users\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n email: varchar(\"email\", { length: 255 }).notNull().unique(),\n passwordHash: varchar(\"password_hash\", { length: 255 }), // NULL for OAuth-only users\n displayName: varchar(\"display_name\", { length: 255 }),\n photoUrl: varchar(\"photo_url\", { length: 500 }),\n emailVerified: boolean(\"email_verified\").default(false).notNull(),\n emailVerificationToken: varchar(\"email_verification_token\", { length: 255 }),\n emailVerificationSentAt: timestamp(\"email_verification_sent_at\"),\n isAnonymous: boolean(\"is_anonymous\").default(false).notNull(),\n roles: text(\"roles\").array().default([]).notNull(),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>().default({}).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull()\n });\n\n\n /**\n * Refresh tokens for long-lived sessions\n */\n const refreshTokens = tableCreator(\"refresh_tokens\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n userId: uuid(\"user_id\").notNull().references(() => users.id, { onDelete: \"cascade\" }),\n tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n expiresAt: timestamp(\"expires_at\").notNull(),\n userAgent: varchar(\"user_agent\", { length: 500 }),\n ipAddress: varchar(\"ip_address\", { length: 45 }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull()\n }, (table) => ({\n uniqueDeviceSession: unique(\"unique_device_session\").on(table.userId, table.userAgent, table.ipAddress)\n }));\n\n /**\n * Password reset tokens for forgot password flow\n */\n const passwordResetTokens = tableCreator(\"password_reset_tokens\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n userId: uuid(\"user_id\").notNull().references(() => users.id, { onDelete: \"cascade\" }),\n tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n expiresAt: timestamp(\"expires_at\").notNull(),\n usedAt: timestamp(\"used_at\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull()\n });\n\n /**\n * App config - key/value store for custom settings\n */\n const appConfig = tableCreator(\"app_config\", {\n key: varchar(\"key\", { length: 100 }).primaryKey(),\n value: jsonb(\"value\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull()\n });\n\n /**\n * User identities - maps external OAuth profiles back to local users\n */\n const userIdentities = tableCreator(\"user_identities\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n userId: uuid(\"user_id\").notNull().references(() => users.id, { onDelete: \"cascade\" }),\n provider: varchar(\"provider\", { length: 50 }).notNull(), // e.g. 'google', 'linkedin'\n providerId: varchar(\"provider_id\", { length: 255 }).notNull(),\n profileData: jsonb(\"profile_data\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull()\n }, (table) => ({\n uniqueProviderId: unique(\"unique_provider_id\").on(table.provider, table.providerId)\n }));\n\n /**\n * MFA factors table - stores enrolled MFA methods\n */\n const mfaFactors = tableCreator(\"mfa_factors\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n userId: uuid(\"user_id\").notNull().references(() => users.id, { onDelete: \"cascade\" }),\n factorType: varchar(\"factor_type\", { length: 20 }).notNull(), // 'totp'\n secretEncrypted: varchar(\"secret_encrypted\", { length: 500 }).notNull(),\n friendlyName: varchar(\"friendly_name\", { length: 255 }),\n verified: boolean(\"verified\").default(false).notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull()\n });\n\n /**\n * MFA challenges table - tracks active MFA verification attempts\n */\n const mfaChallenges = tableCreator(\"mfa_challenges\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n factorId: uuid(\"factor_id\").notNull().references(() => mfaFactors.id, { onDelete: \"cascade\" }),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n verifiedAt: timestamp(\"verified_at\"),\n ipAddress: varchar(\"ip_address\", { length: 45 }),\n expiresAt: timestamp(\"expires_at\").notNull()\n });\n\n /**\n * Recovery codes table - backup codes for MFA\n */\n const recoveryCodes = tableCreator(\"recovery_codes\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n userId: uuid(\"user_id\").notNull().references(() => users.id, { onDelete: \"cascade\" }),\n codeHash: varchar(\"code_hash\", { length: 255 }).notNull(),\n usedAt: timestamp(\"used_at\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull()\n });\n\n return {\n usersSchema,\n users,\n refreshTokens,\n passwordResetTokens,\n appConfig,\n userIdentities,\n mfaFactors,\n mfaChallenges,\n recoveryCodes\n };\n}\n\n// Instantiate default schema and tables using the default \"rebase\" schema\nconst defaultAuthSchema = createAuthSchema(\"rebase\");\n\nexport const usersSchema = defaultAuthSchema.usersSchema;\n\nexport const users = defaultAuthSchema.users;\nexport const refreshTokens = defaultAuthSchema.refreshTokens;\nexport const passwordResetTokens = defaultAuthSchema.passwordResetTokens;\nexport const appConfig = defaultAuthSchema.appConfig;\nexport const userIdentities = defaultAuthSchema.userIdentities;\nexport const mfaFactors = defaultAuthSchema.mfaFactors;\nexport const mfaChallenges = defaultAuthSchema.mfaChallenges;\nexport const recoveryCodes = defaultAuthSchema.recoveryCodes;\n\n// Relations\nexport const usersRelations = relations(users, ({ many }) => ({\n refreshTokens: many(refreshTokens),\n passwordResetTokens: many(passwordResetTokens),\n userIdentities: many(userIdentities),\n mfaFactors: many(mfaFactors),\n recoveryCodes: many(recoveryCodes)\n}));\n\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({\n user: one(users, {\n fields: [refreshTokens.userId],\n references: [users.id]\n })\n}));\n\nexport const passwordResetTokensRelations = relations(passwordResetTokens, ({ one }) => ({\n user: one(users, {\n fields: [passwordResetTokens.userId],\n references: [users.id]\n })\n}));\n\nexport const userIdentitiesRelations = relations(userIdentities, ({ one }) => ({\n user: one(users, {\n fields: [userIdentities.userId],\n references: [users.id]\n })\n}));\n\nexport const mfaFactorsRelations = relations(mfaFactors, ({ one, many }) => ({\n user: one(users, {\n fields: [mfaFactors.userId],\n references: [users.id]\n }),\n challenges: many(mfaChallenges)\n}));\n\nexport const mfaChallengesRelations = relations(mfaChallenges, ({ one }) => ({\n factor: one(mfaFactors, {\n fields: [mfaChallenges.factorId],\n references: [mfaFactors.id]\n })\n}));\n\nexport const recoveryCodesRelations = relations(recoveryCodes, ({ one }) => ({\n user: one(users, {\n fields: [recoveryCodes.userId],\n references: [users.id]\n })\n}));\n\n// Type exports\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type PasswordResetToken = typeof passwordResetTokens.$inferSelect;\nexport type AppConfig = typeof appConfig.$inferSelect;\nexport type UserIdentity = typeof userIdentities.$inferSelect;\nexport type NewUserIdentity = typeof userIdentities.$inferInsert;\nexport type MfaFactorRow = typeof mfaFactors.$inferSelect;\nexport type MfaChallengeRow = typeof mfaChallenges.$inferSelect;\nexport type RecoveryCodeRow = typeof recoveryCodes.$inferSelect;\n","import { EntityCollection, NumberProperty, Property, Relation, RelationProperty, SecurityOperation, SecurityRule, StringProperty, isPostgresCollection, DateProperty, ArrayProperty, MapProperty, ReferenceProperty, VectorProperty, BinaryProperty } from \"@rebasepro/types\";\nimport { getPrimaryKeys } from \"../services/entity-helpers\";\nimport { getEnumVarName, getTableName, getTableVarName, resolveCollectionRelations, findRelation } from \"@rebasepro/common\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { createHash } from \"crypto\";\nimport { logger } from \"@rebasepro/server-core\";\n// --- Helper Functions ---\n\n/**\n * Resolve the SQL column name for a property.\n * Uses the explicit `columnName` when set (e.g. from introspection),\n * falling back to `toSnakeCase(propName)` for manually-authored collections.\n */\nconst resolveColumnName = (propName: string, prop?: Property | null): string => {\n if (prop && \"columnName\" in prop && typeof prop.columnName === \"string\") {\n return prop.columnName;\n }\n return toSnakeCase(propName);\n};\n\nconst getPrimaryKeyProp = (collection: EntityCollection): { name: string, type: \"string\" | \"number\", isUuid: boolean } => {\n if (collection.properties) {\n const idPropEntry = Object.entries(collection.properties).find(([_, prop]) => \"isId\" in (prop as unknown as object) && Boolean((prop as unknown as Record<string, unknown>).isId));\n if (idPropEntry) {\n const prop = idPropEntry[1] as unknown as Property;\n const isUuid = prop.type === \"string\" && \"isId\" in prop && (prop as unknown as StringProperty).isId === \"uuid\";\n return { name: idPropEntry[0],\ntype: prop.type === \"number\" ? \"number\" : \"string\",\nisUuid };\n }\n }\n // Fallback\n const idProp = collection.properties?.[\"id\"] as unknown as Property | undefined;\n if (idProp?.type === \"number\") {\n return { name: \"id\",\ntype: \"number\",\nisUuid: false };\n }\n const isUuid = idProp?.type === \"string\" && \"isId\" in idProp && (idProp as unknown as StringProperty).isId === \"uuid\";\n return { name: \"id\",\ntype: \"string\",\nisUuid: isUuid ?? false };\n};\n\n/**\n * Given a raw DB column name (e.g. \"client_id\"), find the Drizzle property key\n * on the collection that maps to that column. A property matches if:\n * (a) it has an explicit `columnName` equal to the given column, OR\n * (b) its snake_case form equals the given column.\n *\n * Returns the property key (the Drizzle object key) if found, or the original\n * column name as a fallback.\n */\nconst resolvePropertyKeyForColumn = (collection: EntityCollection, column: string): string => {\n if (!collection.properties) return column;\n for (const [propKey, prop] of Object.entries(collection.properties)) {\n const p = prop as Property;\n // Explicit columnName match\n if (\"columnName\" in p && typeof (p as unknown as Record<string, unknown>).columnName === \"string\") {\n if ((p as unknown as Record<string, unknown>).columnName === column) return propKey;\n }\n // Convention match: snake_case(propKey) === column\n if (toSnakeCase(propKey) === column) return propKey;\n // Exact match (propKey is already the column name)\n if (propKey === column) return propKey;\n }\n return column;\n};\n\nconst isNumericId = (collection: EntityCollection): boolean => {\n return getPrimaryKeyProp(collection).type === \"number\";\n};\n\nconst getPrimaryKeyName = (collection: EntityCollection): string => {\n return getPrimaryKeyProp(collection).name;\n};\n\nconst isIdProperty = (propName: string, prop: Property, collection: EntityCollection): boolean => {\n if (\"isId\" in prop && Boolean(prop.isId)) return true;\n\n // We only fallback to \"id\" if NO property is explicitly marked with `isId: true` or a generator string\n const hasExplicitId = Object.values(collection.properties ?? {}).some(p => \"isId\" in (p as unknown as object) && Boolean((p as unknown as Record<string, unknown>).isId));\n return !hasExplicitId && propName === \"id\";\n};\n\nconst getDrizzleColumn = (propName: string, prop: Property, collection: EntityCollection, collections: EntityCollection[]): string | null => {\n\n const colName = resolveColumnName(propName, prop);\n let columnDefinition: string;\n\n switch (prop.type) {\n case \"string\": {\n const stringProp = prop as unknown as StringProperty;\n if (stringProp.enum) {\n const enumName = getEnumVarName(getTableName(collection), propName);\n columnDefinition = `${enumName}(\"${colName}\")`;\n } else if (\"isId\" in stringProp && stringProp.isId === \"uuid\") {\n columnDefinition = `uuid(\"${colName}\")`;\n } else if (stringProp.columnType === \"uuid\") {\n columnDefinition = `uuid(\"${colName}\")`;\n } else if (stringProp.columnType === \"text\") {\n columnDefinition = `text(\"${colName}\")`;\n } else if (stringProp.columnType === \"char\") {\n columnDefinition = `char(\"${colName}\")`;\n } else {\n columnDefinition = `varchar(\"${colName}\")`;\n }\n if (isIdProperty(propName, prop, collection)) {\n columnDefinition += \".primaryKey()\";\n }\n if (\"isId\" in stringProp && stringProp.isId !== \"manual\" && stringProp.isId !== true) {\n if (stringProp.isId === \"uuid\") {\n columnDefinition += \".defaultRandom()\";\n } else if (stringProp.isId === \"cuid\") {\n columnDefinition += \".default(sql`cuid()`)\";\n } else if (typeof stringProp.isId === \"string\") {\n const sqlContent = stringProp.isId.startsWith(\"sql`\") && stringProp.isId.endsWith(\"`\")\n ? stringProp.isId.substring(4, stringProp.isId.length - 1)\n : stringProp.isId;\n columnDefinition += `.default(sql\\`${sqlContent}\\`)`;\n }\n }\n if (stringProp.validation?.unique) {\n columnDefinition += \".unique()\";\n }\n break;\n }\n case \"number\": {\n const numProp = prop as unknown as NumberProperty;\n const isId = isIdProperty(propName, prop, collection);\n\n let baseType = (numProp.validation?.integer || isId) ? `integer(\"${colName}\")` : `numeric(\"${colName}\")`;\n if (numProp.columnType) {\n if (numProp.columnType === \"double precision\") baseType = `doublePrecision(\"${colName}\")`;\n else baseType = `${numProp.columnType}(\"${colName}\")`;\n }\n\n if (\"isId\" in numProp && numProp.isId === \"increment\") {\n columnDefinition = `${baseType}.generatedByDefaultAsIdentity()`;\n } else if (\"isId\" in numProp && typeof numProp.isId === \"string\" && numProp.isId !== \"manual\") {\n columnDefinition = baseType;\n const sqlContent = numProp.isId.startsWith(\"sql`\") && numProp.isId.endsWith(\"`\")\n ? numProp.isId.substring(4, numProp.isId.length - 1)\n : numProp.isId;\n columnDefinition += `.default(sql\\`${sqlContent}\\`)`;\n } else {\n columnDefinition = baseType;\n }\n\n if (isId) {\n columnDefinition += \".primaryKey()\";\n }\n if (numProp.validation?.unique) {\n columnDefinition += \".unique()\";\n }\n break;\n }\n case \"boolean\":\n columnDefinition = `boolean(\"${colName}\")`;\n break;\n case \"date\": {\n const dateProp = prop as DateProperty;\n if (dateProp.columnType === \"date\") {\n columnDefinition = `date(\"${colName}\", { mode: 'string' })`;\n } else if (dateProp.columnType === \"time\") {\n columnDefinition = `time(\"${colName}\")`;\n } else {\n columnDefinition = `timestamp(\"${colName}\", { withTimezone: true, mode: 'string' })`;\n }\n // autoValue: database-level default for initial value on INSERT\n if (dateProp.autoValue === \"on_create\" || dateProp.autoValue === \"on_update\") {\n columnDefinition += \".default(sql`now()`)\";\n }\n break;\n }\n case \"map\": {\n const mapProp = prop as MapProperty;\n if (mapProp.columnType === \"json\") {\n columnDefinition = `json(\"${colName}\")`;\n } else {\n columnDefinition = `jsonb(\"${colName}\")`;\n }\n break;\n }\n case \"array\": {\n const arrayProp = prop as ArrayProperty;\n let colType = arrayProp.columnType;\n if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {\n const ofProp = arrayProp.of as Property;\n if (ofProp.type === \"string\") {\n colType = \"text[]\";\n } else if (ofProp.type === \"number\") {\n colType = ofProp.validation?.integer ? \"integer[]\" : \"numeric[]\";\n } else if (ofProp.type === \"boolean\") {\n colType = \"boolean[]\";\n }\n }\n\n if (colType === \"json\") {\n columnDefinition = `json(\"${colName}\")`;\n } else if (colType === \"text[]\") {\n columnDefinition = `text(\"${colName}\").array()`;\n } else if (colType === \"integer[]\") {\n columnDefinition = `integer(\"${colName}\").array()`;\n } else if (colType === \"boolean[]\") {\n columnDefinition = `boolean(\"${colName}\").array()`;\n } else if (colType === \"numeric[]\") {\n columnDefinition = `numeric(\"${colName}\").array()`;\n } else {\n columnDefinition = `jsonb(\"${colName}\")`;\n }\n break;\n }\n case \"vector\": {\n const vp = prop as VectorProperty;\n columnDefinition = `vector(\"${colName}\", { dimensions: ${vp.dimensions} })`;\n break;\n }\n case \"binary\": {\n columnDefinition = `customType({ dataType() { return 'bytea'; } })(\"${colName}\")`;\n break;\n }\n case \"relation\": {\n const refProp = prop as RelationProperty;\n const resolvedRelations = resolveCollectionRelations(collection);\n const relation = findRelation(resolvedRelations, refProp.relationName ?? propName);\n\n // Only owning one-to-one/many-to-one relations create a column here.\n if (!relation || relation.direction !== \"owning\" || relation.cardinality !== \"one\") {\n return null;\n }\n\n // The localKey property is the source of truth for the FK column name.\n if (!relation.localKey) {\n logger.warn(`Could not generate column for owning relation '${relation.relationName}' on '${collection.name}': 'localKey' is not defined.`);\n return null;\n }\n\n // If the localKey property is defined elsewhere in the properties, it will be handled there.\n // This logic is for when the relation property itself defines the FK.\n if (collection.properties[relation.localKey] && propName !== relation.localKey) {\n return null;\n }\n\n let targetCollection: EntityCollection;\n try {\n targetCollection = relation.target();\n } catch {\n return null; // Cannot resolve target\n }\n\n const fkColumnName = relation.localKey;\n const targetTableVar = getTableVarName(getTableName(targetCollection));\n const pkProp = getPrimaryKeyProp(targetCollection);\n const targetIdField = pkProp.name;\n const baseColumn = pkProp.type === \"number\" ? `integer(\"${fkColumnName}\")` : (pkProp.isUuid ? `uuid(\"${fkColumnName}\")` : `varchar(\"${fkColumnName}\")`);\n\n const onUpdate = relation.onUpdate ? `onUpdate: \"${relation.onUpdate}\"` : \"\";\n const required = prop.validation?.required;\n const onDeleteVal = relation.onDelete ?? (required ? \"cascade\" : \"set null\");\n const onDelete = `onDelete: \\\"${onDeleteVal}\\\"`;\n\n const refOptionsParts = [onUpdate, onDelete].filter(Boolean);\n const refOptions = refOptionsParts.length > 0 ? `{ ${refOptionsParts.join(\", \")} }` : \"\";\n\n let columnDef = `${baseColumn}.references(() => ${targetTableVar}.${targetIdField}${refOptions ? `, ${refOptions}` : \"\"})`;\n\n if (required) {\n columnDef += \".notNull()\";\n }\n\n return ` ${relation.localKey}: ${columnDef}`;\n }\n case \"reference\": {\n const refProp = prop as ReferenceProperty;\n const targetCollection = collections.find(c => c.slug === refProp.path || getTableName(c) === refProp.path);\n if (!targetCollection) {\n columnDefinition = `varchar(\"${colName}\")`;\n break;\n }\n\n const pkProp = getPrimaryKeyProp(targetCollection);\n const targetTableVar = getTableVarName(getTableName(targetCollection));\n const targetIdField = pkProp.name;\n const baseColumn = pkProp.type === \"number\" ? `integer(\"${colName}\")` : (pkProp.isUuid ? `uuid(\"${colName}\")` : `varchar(\"${colName}\")`);\n\n const required = prop.validation?.required;\n const onDelete = required ? \"cascade\" : \"set null\";\n const refOptions = `{ onDelete: \"${onDelete}\" }`;\n\n columnDefinition = `${baseColumn}.references(() => ${targetTableVar}.${targetIdField}, ${refOptions})`;\n if (required) {\n columnDefinition += \".notNull()\";\n }\n // Skip the standard notNull() handling below because we did it here with references\n return ` ${propName}: ${columnDefinition}`;\n }\n default:\n return null;\n }\n\n if (prop.validation?.required) {\n columnDefinition += \".notNull()\";\n }\n\n return ` ${propName}: ${columnDefinition}`;\n};\n\n/**\n * Resolves a raw SQL string, replacing `{column_name}` with `${table.column_name}`.\n * The result is wrapped in a Drizzle sql`` template literal.\n */\nconst resolveRawSql = (expression: string): string => {\n // Replace {column_name} with column_name directly (so Drizzle-kit can parse it as a static string)\n const resolved = expression.replace(/\\{(\\w+)\\}/g, (_, col) => col);\n return `sql\\`${resolved}\\``;\n};\n\n/**\n * Wraps a SQL clause with a role check using AND.\n * Generates: `(<clause>) AND (string_to_array(auth.roles(), ',') && ARRAY['<role1>','<role2>'])`\n */\nconst wrapWithRoleCheck = (clause: string, roles: string[]): string => {\n const rolesArrayString = `ARRAY[${roles.map(r => `'${r}'`).join(\",\")}]`;\n const roleCondition = `string_to_array(auth.roles(), ',') && ${rolesArrayString}`;\n return `sql\\`(${unwrapSql(clause)}) AND (${roleCondition})\\``;\n};\n\n/**\n * Extracts the inner expression from a `sql\\`...\\`` wrapper.\n */\nconst unwrapSql = (sqlExpr: string): string => {\n const match = sqlExpr.match(/^sql`(.*)`$/s);\n return match ? match[1] : sqlExpr;\n};\n\n/**\n * Builds the USING clause for a policy based on shortcuts or raw SQL.\n */\nconst buildUsingClause = (rule: SecurityRule, collection: EntityCollection): string | null => {\n if (rule.using) {\n return resolveRawSql(rule.using);\n }\n if (rule.access === \"public\") {\n return \"sql`true`\";\n }\n if (rule.ownerField) {\n const prop = collection.properties?.[rule.ownerField];\n const colName = resolveColumnName(rule.ownerField, prop);\n return `sql\\`${colName} = auth.uid()\\``;\n }\n return null;\n};\n\n/**\n * Builds the WITH CHECK clause for a policy based on shortcuts or raw SQL.\n * Falls back to the USING clause if not explicitly provided.\n */\nconst buildWithCheckClause = (rule: SecurityRule, collection: EntityCollection): string | null => {\n if (rule.withCheck) {\n return resolveRawSql(rule.withCheck);\n }\n // For insert/update/all, fall back to using clause if withCheck not specified\n return buildUsingClause(rule, collection);\n};\n\n/**\n * Generates a deterministic hash based on the rule configuration.\n */\nconst getPolicyNameHash = (rule: SecurityRule): string => {\n const data = JSON.stringify({\n a: rule.access,\n m: rule.mode,\n op: rule.operation,\n ops: rule.operations?.slice().sort(),\n own: rule.ownerField,\n rol: rule.roles?.slice().sort(),\n pg: rule.pgRoles?.slice().sort(),\n u: rule.using,\n w: rule.withCheck\n });\n return createHash(\"sha1\").update(data).digest(\"hex\").substring(0, 7);\n};\n\n/**\n * Generates Drizzle pgPolicy() calls from a declarative SecurityRule definition.\n *\n * Supports the full spectrum:\n * - Convenience shortcuts: ownerField, access, roles\n * - Raw SQL: using, withCheck\n * - Mode: permissive (default) or restrictive\n * - operations[] array: generates one policy per operation\n * - Combinations: roles + ownerField, roles + raw SQL, etc.\n */\nconst generatePolicyCode = (collection: EntityCollection, rule: SecurityRule, index: number): string => {\n const tableName = getTableName(collection);\n // Resolve operations: operations[] takes precedence over operation (singular)\n const ops: SecurityOperation[] = rule.operations && rule.operations.length > 0\n ? rule.operations\n : [rule.operation ?? \"all\"];\n\n const ruleHash = getPolicyNameHash(rule);\n\n // Generate one pgPolicy per operation\n return ops.map((op, opIdx) => {\n const policyName = rule.name\n ? (ops.length > 1 ? `${rule.name}_${op}` : rule.name)\n : `${tableName}_${op}_${ruleHash}${ops.length > 1 ? `_${opIdx}` : \"\"}`;\n\n return generateSinglePolicyCode(collection, rule, op, policyName);\n }).join(\"\");\n};\n\n/**\n * Generates a single pgPolicy() call for one specific operation.\n */\nconst generateSinglePolicyCode = (collection: EntityCollection, rule: SecurityRule, operation: SecurityOperation, policyName: string): string => {\n const mode = rule.mode ?? \"permissive\";\n const roles = rule.roles ? [...rule.roles].sort() : undefined;\n\n // Determine which clauses this operation needs:\n // SELECT, DELETE → USING only\n // INSERT → WITH CHECK only\n // UPDATE, ALL → both USING and WITH CHECK\n const needsUsing = operation !== \"insert\";\n const needsWithCheck = operation !== \"select\" && operation !== \"delete\";\n\n let usingClause = needsUsing ? buildUsingClause(rule, collection) : null;\n let withCheckClause = needsWithCheck ? buildWithCheckClause(rule, collection) : null;\n\n // If roles are specified, wrap existing clauses with role check,\n // or generate a roles-only clause.\n if (roles && roles.length > 0) {\n if (usingClause) {\n usingClause = wrapWithRoleCheck(usingClause, roles);\n } else if (needsUsing) {\n // Roles-only rule (e.g. { operation: \"select\", roles: [\"admin\"] })\n const rolesArrayString = `ARRAY[${roles.map(r => `'${r}'`).join(\",\")}]`;\n usingClause = `sql\\`string_to_array(auth.roles(), ',') && ${rolesArrayString}\\``;\n }\n if (withCheckClause) {\n withCheckClause = wrapWithRoleCheck(withCheckClause, roles);\n } else if (needsWithCheck) {\n const rolesArrayString = `ARRAY[${roles.map(r => `'${r}'`).join(\",\")}]`;\n withCheckClause = `sql\\`string_to_array(auth.roles(), ',') && ${rolesArrayString}\\``;\n }\n }\n\n // Fallback: if we still have no clauses, deny all (safety net)\n if (!usingClause && needsUsing) {\n usingClause = \"sql`false`\";\n }\n if (!withCheckClause && needsWithCheck) {\n withCheckClause = \"sql`false`\";\n }\n\n // Build the policy options object\n const parts: string[] = [];\n parts.push(`as: \"${mode}\"`);\n parts.push(`for: \"${operation}\"`);\n const toRoles = rule.pgRoles ? [...rule.pgRoles].sort() : [\"public\"];\n parts.push(`to: [${toRoles.map(r => `\"${r}\"`).join(\", \")}]`);\n if (usingClause) parts.push(`using: ${usingClause}`);\n if (withCheckClause) parts.push(`withCheck: ${withCheckClause}`);\n\n return ` pgPolicy(\"${policyName}\", { ${parts.join(\", \")} }),\\n`;\n};\n\n/**\n * Computes a deterministic shared relation name for Drizzle.\n *\n * Drizzle requires both sides of a relation (owning + inverse) to use the\n * exact same `relationName` string so it can pair them. Each collection\n * definition may use a different local `relationName`, so we need a canonical\n * form that both sides can independently compute.\n *\n * Strategy: `{owningTable}_{foreignKey}`\n * - owning side → `{thisTable}_{localKey}` e.g. \"jobs_company_id\"\n * - inverse side → `{targetTable}_{foreignKeyOnTarget}` e.g. \"jobs_company_id\"\n *\n * For M2M with junction tables the owning relation name is already shared via\n * the junction table wiring, so we keep it as-is.\n *\n * Falls back to the local relation name when the counterpart can't be resolved.\n */\nconst computeSharedRelationName = (\n rel: Relation,\n sourceCollection: EntityCollection,\n _collections: EntityCollection[]\n): string => {\n const fallback = rel.relationName ?? toSnakeCase(rel.target().slug);\n\n // --- owning one (belongs-to) ---\n if (rel.direction === \"owning\" && rel.cardinality === \"one\" && rel.localKey) {\n // Normalise the localKey to the actual Drizzle property name so that\n // the owning side produces the same relation name as the inverse side\n // (which resolves foreignKeyOnTarget via the same helper).\n const normalisedKey = resolvePropertyKeyForColumn(sourceCollection, rel.localKey);\n return `${getTableName(sourceCollection)}_${normalisedKey}`;\n }\n\n // --- inverse many (one-to-many has-many) ---\n if (rel.direction === \"inverse\" && rel.cardinality === \"many\" && rel.foreignKeyOnTarget) {\n // The owning table is the *target*, the FK column is foreignKeyOnTarget.\n // Resolve to the Drizzle property key on the target so it matches the\n // owning side's normalised localKey.\n try {\n const targetCollection = rel.target();\n const normalisedFK = resolvePropertyKeyForColumn(targetCollection, rel.foreignKeyOnTarget);\n return `${getTableName(targetCollection)}_${normalisedFK}`;\n } catch {\n return fallback;\n }\n }\n\n // --- inverse one (one-to-one inverse) ---\n if (rel.direction === \"inverse\" && rel.cardinality === \"one\") {\n if (rel.foreignKeyOnTarget) {\n // FK lives on the target table — resolve to Drizzle property key\n try {\n const targetCollection = rel.target();\n const normalisedFK = resolvePropertyKeyForColumn(targetCollection, rel.foreignKeyOnTarget);\n return `${getTableName(targetCollection)}_${normalisedFK}`;\n } catch {\n return fallback;\n }\n }\n // No explicit foreignKeyOnTarget — try to find the corresponding owning relation\n try {\n const targetCollection = rel.target();\n const targetResolvedRelations = resolveCollectionRelations(targetCollection);\n const correspondingRelation = Object.values(targetResolvedRelations).find(targetRel =>\n targetRel.direction === \"owning\" &&\n targetRel.cardinality === \"one\" &&\n targetRel.localKey &&\n targetRel.target().slug === sourceCollection.slug\n );\n if (correspondingRelation && correspondingRelation.localKey) {\n return `${getTableName(targetCollection)}_${correspondingRelation.localKey}`;\n }\n } catch {\n // ignore\n }\n return fallback;\n }\n\n // --- M2M owning (through) — keep local name (already shared via junction wiring) ---\n // --- M2M inverse — keep local name ---\n // --- joinPath — not emitted as Drizzle relations ---\n return fallback;\n};\n\n// --- Main Schema Generation Logic ---\nexport const generateSchema = async (collections: EntityCollection[], stripPolicies = false): Promise<string> => {\n let schemaContent = \"// This file is auto-generated by the Rebase Drizzle generator. Do not edit manually.\\n\\n\";\n\n\n const hasUuid = collections.some(c =>\n c.properties && Object.values(c.properties).some(\n (p: Property) => p.type === \"string\" && ((p as unknown as Record<string, unknown>).autoValue === \"uuid\" || (p as unknown as Record<string, unknown>).isId === \"uuid\")\n )\n );\n\n const hasVector = collections.some(c =>\n c.properties && Object.values(c.properties).some(\n (p: Property) => p.type === \"vector\"\n )\n );\n\n const hasBinary = collections.some(c =>\n c.properties && Object.values(c.properties).some(\n (p: Property) => p.type === \"binary\"\n )\n );\n\n // Always import pgPolicy and sql — RLS is enabled on every table (secure by default)\n const pgCoreImports = [\"primaryKey\", \"pgTable\", \"integer\", \"varchar\", \"text\", \"char\", \"boolean\", \"timestamp\", \"date\", \"time\", \"jsonb\", \"json\", \"pgEnum\", \"numeric\", \"real\", \"doublePrecision\", \"bigint\", \"serial\", \"bigserial\", \"pgPolicy\"];\n if (hasUuid) pgCoreImports.push(\"uuid\");\n if (hasVector) pgCoreImports.push(\"vector\");\n if (hasBinary) pgCoreImports.push(\"customType\");\n\n const uniqueSchemas = Array.from(new Set(\n collections.map(c => isPostgresCollection(c) ? c.schema : undefined).filter(Boolean)\n ));\n if (uniqueSchemas.length > 0) {\n pgCoreImports.push(\"pgSchema\");\n }\n\n schemaContent += `import { ${pgCoreImports.join(\", \")} } from 'drizzle-orm/pg-core';\\n`;\n schemaContent += \"import { relations as drizzleRelations, sql } from 'drizzle-orm';\\n\\n\";\n\n uniqueSchemas.forEach(schema => {\n schemaContent += `export const ${schema}Schema = pgSchema(\"${schema}\");\\n`;\n });\n if (uniqueSchemas.length > 0) {\n schemaContent += \"\\n\";\n }\n\n const exportedTableVars: string[] = [];\n const exportedEnumVars: string[] = [];\n const exportedRelationVars: string[] = [];\n\n const allTablesToGenerate = new Map<string, {\n collection: EntityCollection,\n isJunction?: boolean,\n relation?: Relation,\n sourceCollection?: EntityCollection\n }>();\n\n // 1. Generate Enums\n collections.forEach(collection => {\n const collectionPath = getTableName(collection);\n Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {\n\n if ((\"enum\" in prop) && (prop.type === \"string\" || prop.type === \"number\") && prop.enum) {\n const enumVarName = getEnumVarName(collectionPath, propName);\n const enumDbName = `${collectionPath}_${resolveColumnName(propName, prop)}`;\n const values = Array.isArray(prop.enum)\n ? prop.enum.map(v => String(v.id ?? v))\n : Object.keys(prop.enum);\n if (values.length > 0) {\n schemaContent += `export const ${enumVarName} = pgEnum(\\\"${enumDbName}\\\", [${values.map(v => `'${v}'`).join(\", \")}]);\\n`;\n if (!exportedEnumVars.includes(enumVarName)) exportedEnumVars.push(enumVarName);\n }\n }\n });\n });\n schemaContent += \"\\n\";\n\n // 2. Identify all tables (collections and junction tables only)\n for (const collection of collections) {\n const tableName = getTableName(collection);\n if (tableName) {\n allTablesToGenerate.set(tableName, { collection });\n }\n\n const resolvedRelations = resolveCollectionRelations(collection);\n for (const relation of Object.values(resolvedRelations)) {\n if (relation.through) { // Standard M2M junction table\n const junctionTableName = relation.through.table;\n if (!allTablesToGenerate.has(junctionTableName)) {\n allTablesToGenerate.set(junctionTableName, {\n collection: {\n table: junctionTableName,\n properties: {}\n } as EntityCollection,\n isJunction: true,\n relation: relation,\n sourceCollection: collection\n });\n }\n }\n // joinPath relations use existing user-controlled tables - no generation needed\n }\n }\n\n // 3. Generate pgTable definitions for all unique tables\n for (const [tableName, {\n collection,\n isJunction,\n relation,\n sourceCollection\n }] of allTablesToGenerate.entries()) {\n const tableVarName = getTableVarName(tableName);\n if (isJunction && relation && sourceCollection && relation.through) {\n const targetCollection = relation.target();\n const schema = (isPostgresCollection(targetCollection) ? targetCollection.schema : undefined) || (isPostgresCollection(sourceCollection) ? sourceCollection.schema : undefined);\n const tableCreator = schema ? `${schema}Schema.table` : \"pgTable\";\n const baseTableName = tableName.includes(\".\") ? tableName.split(\".\").pop()! : tableName;\n const {\n sourceColumn,\n targetColumn\n } = relation.through;\n\n const onDelete = relation.onDelete ?? \"cascade\";\n const refOptions = `{ onDelete: \\\"${onDelete}\\\" }`;\n\n const sourceColType = isNumericId(sourceCollection) ? \"integer\" : (getPrimaryKeyProp(sourceCollection).isUuid ? \"uuid\" : \"varchar\");\n const targetColType = isNumericId(targetCollection) ? \"integer\" : (getPrimaryKeyProp(targetCollection).isUuid ? \"uuid\" : \"varchar\");\n const sourceId = getPrimaryKeyName(sourceCollection);\n const targetId = getPrimaryKeyName(targetCollection);\n\n schemaContent += `export const ${tableVarName} = ${tableCreator}(\\\"${baseTableName}\\\", {\\n`;\n schemaContent += ` ${sourceColumn}: ${sourceColType}(\\\"${sourceColumn}\\\").notNull().references(() => ${getTableVarName(getTableName(sourceCollection))}.${sourceId}, ${refOptions}),\\n`;\n schemaContent += ` ${targetColumn}: ${targetColType}(\\\"${targetColumn}\\\").notNull().references(() => ${getTableVarName(getTableName(targetCollection))}.${targetId}, ${refOptions}),\\n`;\n schemaContent += \"}, (table) => ({\\n\";\n schemaContent += ` pk: primaryKey({ columns: [table.${sourceColumn}, table.${targetColumn}] })\\n`;\n schemaContent += \"}));\\n\\n\";\n } else if (!isJunction) {\n const schema = isPostgresCollection(collection) ? collection.schema : undefined;\n const tableCreator = schema ? `${schema}Schema.table` : \"pgTable\";\n const baseTableName = tableName.includes(\".\") ? tableName.split(\".\").pop()! : tableName;\n schemaContent += `export const ${tableVarName} = ${tableCreator}(\\\"${baseTableName}\\\", {\\n`;\n const columns = new Set<string>();\n Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {\n const columnString = getDrizzleColumn(propName, prop as Property, collection, collections);\n if (columnString) columns.add(columnString);\n\n });\n\n // Backwards compatibility: if no id/primary key column is found in properties, but `id` wasn't explicitly provided\n // We should generate a basic id column if one was completely omitted.\n const hasIdColumn = Array.from(columns).some(col => col.includes(\".primaryKey()\"));\n if (!hasIdColumn) {\n columns.add(\" id: varchar(\\\"id\\\").primaryKey()\");\n }\n\n schemaContent += `${Array.from(columns).join(\",\\n\")}`;\n\n const securityRules = isPostgresCollection(collection) ? collection.securityRules : undefined;\n if (!stripPolicies && securityRules && securityRules.length > 0) {\n schemaContent += \"\\n}, (table) => ([\\n\";\n securityRules.forEach((rule: SecurityRule, idx: number) => {\n schemaContent += generatePolicyCode(collection, rule, idx);\n });\n schemaContent += \"])).enableRLS();\\n\\n\";\n } else {\n // No explicit policies — RLS enabled with deny-all default (Postgres denies\n // everything when RLS is on and no permissive policies exist).\n schemaContent += \"\\n}).enableRLS();\\n\\n\";\n }\n }\n if (!exportedTableVars.includes(tableVarName)) exportedTableVars.push(tableVarName);\n }\n\n // 4. Generate Drizzle Relations\n for (const [tableName, {\n collection,\n isJunction\n }] of allTablesToGenerate.entries()) {\n const tableVarName = getTableVarName(tableName);\n const tableRelations: string[] = [];\n\n if (isJunction) {\n const relationInfo = Array.from(allTablesToGenerate.values()).find(v => v.isJunction && getTableName(v.collection) === tableName);\n if (relationInfo && relationInfo.relation && relationInfo.sourceCollection && relationInfo.relation.through) {\n const {\n relation,\n sourceCollection\n } = relationInfo;\n const targetCollection = relation.target();\n const sourceTableVar = getTableVarName(getTableName(sourceCollection));\n const targetTableVar = getTableVarName(getTableName(targetCollection));\n const sourceId = getPrimaryKeyName(sourceCollection);\n const targetId = getPrimaryKeyName(targetCollection);\n\n if (!relation?.through)\n throw new Error(\"Internal, the relation should have a through property. Relations passed to this script should sanitized first with sanitizeRelation().\");\n\n // The owning relation's name — used on the source side of the junction\n const owningRelationName = relation.relationName ?? toSnakeCase(getTableName(targetCollection));\n\n // Find the inverse relation name on the target collection (if any)\n // This is needed so the junction's target-side one() can pair with the\n // inverse many() on the target table.\n let inverseRelationName: string | null = null;\n try {\n const targetRelations = resolveCollectionRelations(targetCollection);\n for (const [, targetRel] of Object.entries(targetRelations)) {\n if (targetRel.direction === \"inverse\" &&\n targetRel.cardinality === \"many\" &&\n targetRel.inverseRelationName === owningRelationName) {\n inverseRelationName = targetRel.relationName ?? null;\n break;\n }\n }\n } catch {\n // ignore — inverse side may not exist\n }\n\n // Source side one(): pairs with owning table's many(junctionTable, { relationName })\n tableRelations.push(` \"${relation.through.sourceColumn}\": one(${sourceTableVar}, {\\n fields: [${tableVarName}.${relation.through.sourceColumn}],\\n references: [${sourceTableVar}.${sourceId}],\\n relationName: \\\"${owningRelationName}\\\"\\n })`);\n\n // Target side one(): pairs with inverse table's many(junctionTable, { relationName })\n // Always emit a relationName to avoid collisions with the source-side's owningRelationName.\n // When no inverse relation exists on the target collection, synthesize a unique name.\n const targetRelationName = inverseRelationName\n ? inverseRelationName\n : `${tableName}_${relation.through.targetColumn}`;\n tableRelations.push(` \"${relation.through.targetColumn}\": one(${targetTableVar}, {\\n fields: [${tableVarName}.${relation.through.targetColumn}],\\n references: [${targetTableVar}.${targetId}],\\n relationName: \"${targetRelationName}\"\\n })`);\n }\n } else {\n const resolvedRelations = resolveCollectionRelations(collection);\n // Defensive safety net: track emitted `drizzleRelationName` values\n // to prevent duplicate one()/many() entries in the generated schema.\n // The root deduplication happens inside resolveCollectionRelations,\n // but this guards against any future regressions in that utility.\n const emittedRelationNames = new Set<string>();\n for (const [relationKey, rel] of Object.entries(resolvedRelations)) {\n try {\n const target = rel.target();\n const targetTableVar = getTableVarName(getTableName(target));\n\n // Compute a deterministic shared relationName for Drizzle.\n // Both sides of an owning/inverse pair MUST share the same\n // relationName, otherwise Drizzle cannot pair them.\n //\n // Strategy: use \"{ownerTable}_{foreignKey}\" which is\n // computable from either side:\n // - owning side: {thisTable}_{localKey}\n // - inverse side: {targetTable}_{foreignKeyOnTarget}\n const drizzleRelationName = computeSharedRelationName(rel, collection, collections);\n\n // Skip if we've already emitted a relation with this drizzleRelationName\n // for this table — prevents duplicate definitions when\n // resolveCollectionRelations returns alias entries for the same FK.\n const deduplicationKey = `${drizzleRelationName}::${rel.direction}`;\n if (emittedRelationNames.has(deduplicationKey)) continue;\n emittedRelationNames.add(deduplicationKey);\n\n if (rel.cardinality === \"one\") {\n if (rel.direction === \"owning\" && rel.localKey) {\n tableRelations.push(` \"${relationKey}\": one(${targetTableVar}, {\\n fields: [${tableVarName}.${rel.localKey}],\\n references: [${targetTableVar}.${getPrimaryKeyName(target)}],\\n relationName: \\\"${drizzleRelationName}\\\"\\n })`);\n } else if (rel.direction === \"inverse\") {\n // Inverse one-to-one: the FK lives on the TARGET table, not here.\n // Drizzle pairs inverse relations via `relationName` alone — specifying\n // `fields`/`references` on the inverse side is invalid and causes\n // `normalizeRelation` to crash with \"Cannot read properties of\n // undefined (reading 'referencedTable')\".\n tableRelations.push(` \"${relationKey}\": one(${targetTableVar}, {\\n relationName: \\\"${drizzleRelationName}\\\"\\n })`);\n }\n } else if (rel.cardinality === \"many\") {\n if (rel.direction === \"inverse\" && rel.foreignKeyOnTarget) {\n // One-to-many inverse relation\n tableRelations.push(` \"${relationKey}\": many(${targetTableVar}, { relationName: \\\"${drizzleRelationName}\\\" })`);\n } else if (rel.through) {\n // Many-to-many owning relation with explicit junction table\n const junctionTableVar = getTableVarName(rel.through.table);\n tableRelations.push(` \"${relationKey}\": many(${junctionTableVar}, { relationName: \\\"${drizzleRelationName}\\\" })`);\n } else if (rel.direction === \"inverse\" && rel.inverseRelationName) {\n // Many-to-many inverse relation - find the corresponding owning relation's junction table\n try {\n const targetCollection = rel.target();\n const targetResolvedRelations = resolveCollectionRelations(targetCollection);\n\n // Find the corresponding owning many-to-many relation on the target\n const correspondingRelation = Object.values(targetResolvedRelations).find(targetRel =>\n targetRel.direction === \"owning\" &&\n targetRel.cardinality === \"many\" &&\n targetRel.through &&\n targetRel.relationName === rel.inverseRelationName\n );\n\n if (correspondingRelation && correspondingRelation.through) {\n const junctionTableVar = getTableVarName(correspondingRelation.through.table);\n tableRelations.push(` \"${relationKey}\": many(${junctionTableVar}, { relationName: \\\"${drizzleRelationName}\\\" })`);\n } else {\n logger.warn(`Could not find corresponding owning many-to-many relation for inverse relation '${relationKey}' on '${collection.name}'`);\n }\n } catch (e) {\n logger.warn(`Could not resolve inverse many-to-many relation '${relationKey}'`, { error: e });\n }\n }\n // joinPath relations don't generate Drizzle relations - they use existing user tables\n }\n } catch (e) {\n logger.warn(`Could not generate relation ${relationKey} for ${collection.name}`, { error: e });\n }\n }\n\n // Synthesize missing reciprocal relations\n for (const otherCollection of collections) {\n if (otherCollection.slug === collection.slug) continue;\n\n const otherRelations = resolveCollectionRelations(otherCollection);\n for (const [otherKey, otherRel] of Object.entries(otherRelations)) {\n if (otherRel.direction === \"inverse\" && otherRel.foreignKeyOnTarget) {\n try {\n const otherTarget = otherRel.target();\n if (otherTarget.slug === collection.slug) {\n const drizzleRelationName = computeSharedRelationName(otherRel, otherCollection, collections);\n const deduplicationKey = `${drizzleRelationName}::owning`;\n\n if (!emittedRelationNames.has(deduplicationKey)) {\n const otherTableVar = getTableVarName(getTableName(otherCollection));\n // Resolve foreignKeyOnTarget to the Drizzle property key\n // on THIS collection (the owning table). The raw FK column\n // name (e.g. \"client_id\") may differ from the property key\n // (e.g. \"clientId\") when `columnName` is set.\n const drizzleFieldKey = resolvePropertyKeyForColumn(collection, otherRel.foreignKeyOnTarget);\n const synthKey = `_synth_${otherTableVar}_${drizzleFieldKey}`;\n tableRelations.push(` \"${synthKey}\": one(${otherTableVar}, {\\n fields: [${tableVarName}.${drizzleFieldKey}],\\n references: [${otherTableVar}.${getPrimaryKeyName(otherCollection)}],\\n relationName: \\\"${drizzleRelationName}\\\"\\n })`);\n emittedRelationNames.add(deduplicationKey);\n }\n }\n } catch (e) {\n // ignore\n }\n }\n }\n }\n }\n\n if (tableRelations.length > 0) {\n const relVarName = `${tableVarName}Relations`;\n schemaContent += `export const ${relVarName} = drizzleRelations(${tableVarName}, ({ one, many }) => ({\\n${tableRelations.join(\",\\n\")}\\n}));\\n\\n`;\n if (!exportedRelationVars.includes(relVarName)) exportedRelationVars.push(relVarName);\n }\n }\n\n // <<< ADDED: Final aggregated exports block\n const tablesExport = `export const tables = { ${exportedTableVars.join(\", \")} };\\n`;\n const enumsExport = `export const enums = { ${exportedEnumVars.join(\", \")} };\\n`;\n const relationsExport = `export const relations = { ${exportedRelationVars.join(\", \")} };\\n\\n`;\n schemaContent += tablesExport + enumsExport + relationsExport;\n\n return schemaContent;\n};\n\n","import { promises as fsPromises } from \"fs\";\nimport * as fs from \"fs\";\nimport path from \"path\";\nimport { pathToFileURL } from \"url\";\nimport chokidar from \"chokidar\";\nimport { generateSchema } from \"./generate-drizzle-schema-logic\";\nimport { EntityCollection } from \"@rebasepro/types\";\nimport { logger } from \"@rebasepro/server-core\";\n\n\n// --- Helper Functions ---\n\nconst formatTerminalText = (text: string, options: {\n bold?: boolean;\n backgroundColor?: \"blue\" | \"green\" | \"red\" | \"yellow\" | \"cyan\" | \"magenta\";\n textColor?: \"white\" | \"black\" | \"red\" | \"green\" | \"yellow\" | \"blue\" | \"magenta\" | \"cyan\";\n} = {}): string => {\n let codes = \"\";\n if (options.bold) codes += \"\\x1b[1m\";\n if (options.backgroundColor) {\n const bgColors = {\n blue: \"\\x1b[44m\",\n green: \"\\x1b[42m\",\n red: \"\\x1b[41m\",\n yellow: \"\\x1b[43m\",\n cyan: \"\\x1b[46m\",\n magenta: \"\\x1b[45m\"\n } as const;\n codes += bgColors[options.backgroundColor];\n }\n if (options.textColor) {\n const textColors = {\n white: \"\\x1b[37m\",\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\"\n } as const;\n codes += textColors[options.textColor];\n }\n return `${codes}${text}\\x1b[0m`;\n};\n\n// --- Execution and Watch Logic ---\n\nconst runGeneration = async (collectionsFilePath?: string, outputPath?: string) => {\n try {\n if (!collectionsFilePath) {\n logger.error(\"Error: No collections file path provided. Skipping schema generation.\");\n return;\n }\n\n const resolvedPath = path.resolve(collectionsFilePath);\n let collections: EntityCollection[] = [];\n const stats = fs.statSync(resolvedPath);\n\n if (stats.isDirectory()) {\n const files = fs.readdirSync(resolvedPath);\n for (const file of files) {\n if ((file.endsWith(\".ts\") || file.endsWith(\".js\")) &&\n !file.includes(\".test.\") &&\n !file.endsWith(\".d.ts\") &&\n file !== \"index.ts\" && file !== \"index.js\") {\n\n const filePath = path.join(resolvedPath, file);\n try {\n const fileUrl = pathToFileURL(filePath).href;\n const dynamicImport = new Function(\"url\", \"return import(url)\");\n const module = await dynamicImport(fileUrl);\n if (module && module.default) {\n collections.push(module.default);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n logger.error(`Error loading ${file}`, { detail: message });\n }\n }\n }\n } else {\n const fileUrl = pathToFileURL(resolvedPath).href + `?t=${Date.now()}`;\n const dynamicImport = new Function(\"url\", \"return import(url)\");\n const imported = await dynamicImport(fileUrl);\n collections = imported.backendCollections || imported.collections;\n }\n\n // If collections directory is empty but exists, or failed to find any, we still want to inject defaults\n if (!collections || !Array.isArray(collections)) {\n collections = [];\n }\n\n\n // Sort collections by slug alphabetically to ensure deterministic schema generation\n collections.sort((a, b) => a.slug.localeCompare(b.slug));\n\n const schemaContent = await generateSchema(collections);\n\n if (outputPath) {\n const outputDir = path.dirname(outputPath);\n await fsPromises.mkdir(outputDir, { recursive: true });\n await fsPromises.writeFile(outputPath, schemaContent);\n logger.info(\"✅ Drizzle schema generated successfully at\", { detail: outputPath });\n } else {\n logger.info(\"✅ Drizzle schema generated successfully.\");\n logger.info(String(schemaContent));\n }\n\n logger.info(`You can now run ${formatTerminalText(\"rebase db generate\", {\n bold: true,\n backgroundColor: \"blue\",\n textColor: \"black\"\n })} to generate the SQL migration files.`);\n\n } catch (error) {\n logger.error(\"Error generating schema\", { error: error });\n }\n};\n\nconst main = () => {\n const collectionsFilePathArg = process.argv.find(arg => arg.startsWith(\"--collections=\"));\n const collectionsFilePath = collectionsFilePathArg ? collectionsFilePathArg.split(\"=\")[1] : process.argv[2];\n\n const outputPathArg = process.argv.find(arg => arg.startsWith(\"--output=\"));\n const outputPath = outputPathArg ? outputPathArg.split(\"=\")[1] : undefined;\n\n const watch = process.argv.includes(\"--watch\");\n\n if (!collectionsFilePath) {\n logger.info(\"Usage: ts-node generate-drizzle-schema.ts <path-to-collections-file> [--output <path-to-output-file>] [--watch]\");\n return;\n }\n\n const resolvedPath = path.resolve(process.cwd(), collectionsFilePath);\n const resolvedOutputPath = outputPath ? path.resolve(process.cwd(), outputPath) : undefined;\n\n if (watch) {\n logger.info(`Watching for changes in ${resolvedPath}...`);\n const watcher = chokidar.watch(resolvedPath, {\n persistent: true,\n ignoreInitial: false\n });\n\n watcher.on(\"all\", (event, filePath) => {\n logger.info(`[${event}] ${filePath}. Regenerating schema...`);\n runGeneration(resolvedPath, resolvedOutputPath);\n });\n } else {\n runGeneration(resolvedPath, resolvedOutputPath);\n }\n};\n\n// This check ensures the script only runs when executed directly\nif (import.meta.url.endsWith(process.argv[1])) {\n main();\n}\n","import { WebSocket } from \"ws\";\nimport { EventEmitter } from \"events\";\nimport { Client as PgClient } from \"pg\";\nimport { randomUUID } from \"crypto\";\nimport { EntityService } from \"./entityService\";\n\nimport { Entity, FetchCollectionProps, ListenCollectionProps, ListenEntityProps, DataDriver, CollectionUpdateMessage, EntityUpdateMessage, CollectionEntityPatchMessage, WebSocketMessage, FilterValues, EntityCollection, RebaseCallContext } from \"@rebasepro/types\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { sql as drizzleSql } from \"drizzle-orm\";\nimport { RealtimeProvider, CollectionSubscriptionConfig, EntitySubscriptionConfig } from \"../interfaces\";\nimport { PostgresCollectionRegistry } from \"../collections/PostgresCollectionRegistry\";\nimport { buildPropertyCallbacks } from \"@rebasepro/common\";\nimport { logger } from \"@rebasepro/server-core\";\nimport { sanitizeErrorForClient } from \"../utils/pg-error-utils\";\n\n/** Channel name used for Postgres LISTEN/NOTIFY cross-instance realtime. */\nconst PG_NOTIFY_CHANNEL = \"rebase_entity_changes\";\n\n/**\n * Auth context stored per-subscription so real-time refetches respect RLS.\n * Mirrors the session variables set by PostgresBackendDriver.withAuth().\n */\nexport interface SubscriptionAuthContext {\n userId: string;\n roles: string[];\n}\n\ninterface DataDriverWithData extends DataDriver {\n data: unknown;\n}\n\ntype RealTimeListenCollectionProps = ListenCollectionProps & {\n subscriptionId: string\n};\n\ntype RealTimeListenEntityProps = ListenEntityProps & { subscriptionId: string };\n\n/**\n * PostgreSQL-specific realtime service.\n * Handles WebSocket connections and subscriptions for real-time entity updates.\n *\n * Implements the RealtimeProvider interface for database abstraction.\n */\nexport class RealtimeService extends EventEmitter implements RealtimeProvider {\n private clients = new Map<string, WebSocket>();\n\n // Broadcast channels: channel name → set of client IDs\n private channels = new Map<string, Set<string>>();\n\n // Presence: channel → Map<clientId, { state, lastSeen }>\n private presence = new Map<string, Map<string, { state: Record<string, unknown>; lastSeen: number }>>();\n private presenceInterval?: ReturnType<typeof setInterval>;\n private static readonly PRESENCE_TIMEOUT_MS = 30000; // 30s\n private entityService: EntityService;\n // Enhanced subscriptions storage with full request parameters\n private _subscriptions = new Map<string, {\n clientId: string;\n type: \"collection\" | \"entity\";\n path: string;\n entityId?: string | number;\n // Store full collection request parameters for proper refetching\n collectionRequest?: {\n filter?: Record<string, unknown>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n databaseId?: string;\n searchString?: string;\n };\n // Auth context for RLS — when set, refetches run in a transaction\n // with set_config('app.user_id', ...) / set_config('app.user_roles', ...)\n authContext?: SubscriptionAuthContext;\n }>();\n\n // Add callback storage for DataDriver subscriptions\n private subscriptionCallbacks = new Map<string, (data: Entity[] | Entity | null) => void>();\n\n private driver?: DataDriver;\n\n // ── Cross-instance LISTEN/NOTIFY ──\n /** Unique identifier for this process instance, used to skip own notifications. */\n private readonly instanceId = `inst_${randomUUID().slice(0, 8)}`;\n /** Dedicated pg.Client for LISTEN (outside the Drizzle pool). */\n private listenClient?: PgClient;\n /** Connection string used for reconnecting the LISTEN client. */\n private listenConnectionString?: string;\n /** Whether cross-instance broadcasting is active. */\n private broadcasting = false;\n /** Reconnection timer handle. */\n private reconnectTimer?: ReturnType<typeof setTimeout>;\n /** Debounce timers for collection refetches to prevent refetch storms. */\n private refetchTimers = new Map<string, ReturnType<typeof setTimeout>>();\n /** Debounce window (ms) for coalescing rapid entity updates into a single correctness refetch. */\n private static readonly REFETCH_DEBOUNCE_MS = 300;\n\n constructor(private db: NodePgDatabase<any>, private registry: PostgresCollectionRegistry) {\n super();\n this.entityService = new EntityService(db, registry);\n }\n\n /** Whether to emit verbose debug logs (disabled in production). */\n private static readonly DEBUG = process.env.NODE_ENV !== \"production\";\n private debugLog(...args: unknown[]) {\n if (RealtimeService.DEBUG) console.debug(...args);\n }\n\n setDataDriver(driver: DataDriver) {\n this.driver = driver;\n }\n\n // Make subscriptions accessible for DataDriver\n get subscriptions() {\n return this._subscriptions;\n }\n\n // Add public method to register DataDriver subscriptions\n registerDataDriverSubscription(subscriptionId: string, subscription: {\n clientId: string;\n type: \"collection\" | \"entity\";\n path: string;\n entityId?: string | number;\n collectionRequest?: {\n filter?: Record<string, unknown>;\n orderBy?: string;\n order?: \"desc\" | \"asc\";\n limit?: number;\n offset?: number;\n startAfter?: Record<string, unknown>;\n databaseId?: string;\n searchString?: string;\n };\n authContext?: SubscriptionAuthContext;\n }) {\n this.debugLog(\"📋 [RealtimeService] Registering DataDriver subscription:\", subscriptionId, subscription.authContext ? \"(with auth)\" : \"(no auth)\");\n this._subscriptions.set(subscriptionId, subscription);\n }\n\n // Add callback management methods\n addSubscriptionCallback(subscriptionId: string, callback: (data: Entity[] | Entity | null) => void) {\n this.debugLog(\"📋 [RealtimeService] Adding callback for subscription:\", subscriptionId);\n this.subscriptionCallbacks.set(subscriptionId, callback);\n }\n\n removeSubscriptionCallback(subscriptionId: string) {\n this.debugLog(\"📋 [RealtimeService] Removing callback for subscription:\", subscriptionId);\n this.subscriptionCallbacks.delete(subscriptionId);\n }\n\n // =============================================================================\n // RealtimeProvider Interface Methods\n // =============================================================================\n\n /**\n * Subscribe to collection changes (RealtimeProvider interface)\n */\n subscribeToCollection(\n subscriptionId: string,\n config: CollectionSubscriptionConfig,\n callback?: (entities: Entity[]) => void\n ): void {\n this._subscriptions.set(subscriptionId, {\n clientId: config.clientId,\n type: \"collection\",\n path: config.path,\n collectionRequest: {\n filter: config.filter as Record<string, unknown> | undefined,\n orderBy: config.orderBy,\n order: config.order,\n limit: config.limit,\n startAfter: config.startAfter as Record<string, unknown> | undefined,\n databaseId: config.databaseId,\n searchString: config.searchString\n }\n });\n\n if (callback) {\n this.subscriptionCallbacks.set(subscriptionId, callback as (data: Entity[] | Entity | null) => void);\n }\n }\n\n /**\n * Subscribe to single entity changes (RealtimeProvider interface)\n */\n subscribeToEntity(\n subscriptionId: string,\n config: EntitySubscriptionConfig,\n callback?: (entity: Entity | null) => void\n ): void {\n this._subscriptions.set(subscriptionId, {\n clientId: config.clientId,\n type: \"entity\",\n path: config.path,\n entityId: config.entityId\n });\n\n if (callback) {\n this.subscriptionCallbacks.set(subscriptionId, callback as (data: Entity[] | Entity | null) => void);\n }\n }\n\n /**\n * Unsubscribe from a subscription (RealtimeProvider interface)\n */\n unsubscribe(subscriptionId: string): void {\n this._subscriptions.delete(subscriptionId);\n this.subscriptionCallbacks.delete(subscriptionId);\n }\n\n // =============================================================================\n // WebSocket Client Management\n // =============================================================================\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 // Public method to handle messages from external sources (like main WebSocket handler)\n async handleClientMessage(clientId: string, message: WebSocketMessage, authContext?: SubscriptionAuthContext) {\n await this.handleMessage(clientId, message, authContext);\n }\n\n async removeClient(clientId: string) {\n this.clients.delete(clientId);\n\n // Remove all subscriptions, callbacks, and pending refetch timers for this client\n for (const [subscriptionId, subscription] of this._subscriptions.entries()) {\n if (subscription.clientId === clientId) {\n this._subscriptions.delete(subscriptionId);\n this.subscriptionCallbacks.delete(subscriptionId);\n\n // Cancel any pending debounced refetch timers\n for (const prefix of [\"ws_\", \"drv_\", \"wse_\", \"drve_\"]) {\n const key = `${prefix}${subscriptionId}`;\n const timer = this.refetchTimers.get(key);\n if (timer) { clearTimeout(timer); this.refetchTimers.delete(key); }\n }\n }\n }\n\n // Remove from all broadcast channels\n for (const [channel, members] of this.channels.entries()) {\n if (members.has(clientId)) {\n members.delete(clientId);\n this.removePresence(clientId, channel);\n if (members.size === 0) this.channels.delete(channel);\n }\n }\n\n // Remove from all presence channels\n for (const [channel] of this.presence) {\n this.removePresence(clientId, channel);\n }\n }\n\n private async handleMessage(clientId: string, message: WebSocketMessage, authContext?: SubscriptionAuthContext) {\n const payload = message.payload as Record<string, unknown> | undefined;\n switch (message.type) {\n case \"subscribe_collection\":\n await this.handleCollectionSubscription(clientId, message.payload as RealTimeListenCollectionProps, authContext);\n break;\n case \"subscribe_entity\":\n await this.handleEntitySubscription(clientId, message.payload as RealTimeListenEntityProps, authContext);\n break;\n case \"unsubscribe\":\n await this.handleUnsubscribe(clientId, message.subscriptionId!);\n break;\n\n // ── Broadcast Channels ──\n case \"join_channel\":\n this.joinChannel(clientId, payload?.channel as string);\n break;\n case \"leave_channel\":\n this.leaveChannel(clientId, payload?.channel as string);\n break;\n case \"broadcast\":\n this.broadcastToChannel(\n clientId,\n payload?.channel as string,\n payload?.event as string,\n payload?.payload\n );\n break;\n\n // ── Presence ──\n case \"presence_track\":\n // Auto-join the channel so presence works without a separate join\n this.joinChannel(clientId, payload?.channel as string);\n this.trackPresence(\n clientId,\n payload?.channel as string,\n payload?.state as Record<string, unknown> ?? {}\n );\n break;\n case \"presence_untrack\":\n this.removePresence(clientId, payload?.channel as string);\n break;\n case \"presence_state\":\n this.sendPresenceState(clientId, payload?.channel as string);\n break;\n\n default:\n this.sendError(clientId, \"Unknown message type \" + message.type, message.subscriptionId);\n }\n }\n\n private async handleCollectionSubscription(clientId: string, request: RealTimeListenCollectionProps, authContext?: SubscriptionAuthContext) {\n const subscriptionId = request.subscriptionId;\n\n try {\n // Early validation: ensure the requested collection exists in the registry\n const collection = this.registry.getCollectionByPath(request.path);\n if (!collection) {\n const registered = this.registry.getCollections().map(c => c.slug).join(\", \");\n const msg = `Collection not found: '${request.path}'. Registered: [${registered}]`;\n logger.error(`[RealtimeService] ${msg}`);\n this.sendError(clientId, msg, subscriptionId);\n return;\n }\n\n // Store subscription with full request parameters and auth context for RLS\n this._subscriptions.set(subscriptionId, {\n clientId,\n type: \"collection\",\n path: request.path,\n collectionRequest: {\n filter: request.filter,\n orderBy: request.orderBy,\n order: request.order,\n limit: request.limit,\n startAfter: request.startAfter as Record<string, unknown> | undefined,\n databaseId: request.collection?.databaseId,\n searchString: request.searchString\n },\n authContext\n });\n\n // Send initial data\n const entities = await this.fetchCollectionWithAuth(\n request.path,\n {\n filter: request.filter,\n orderBy: request.orderBy,\n order: request.order,\n limit: request.limit,\n startAfter: request.startAfter as Record<string, unknown> | undefined,\n searchString: request.searchString\n },\n authContext\n );\n\n this.sendCollectionUpdate(clientId, subscriptionId, entities);\n\n } catch (error) {\n const sanitized = sanitizeErrorForClient(error, request.path);\n this.sendError(clientId, sanitized.message, subscriptionId, sanitized.code);\n }\n }\n\n private async handleEntitySubscription(clientId: string, request: RealTimeListenEntityProps, authContext?: SubscriptionAuthContext) {\n const subscriptionId = request.subscriptionId;\n\n try {\n // Early validation: ensure the requested collection exists in the registry\n const collection = this.registry.getCollectionByPath(request.path);\n if (!collection) {\n const registered = this.registry.getCollections().map(c => c.slug).join(\", \");\n const msg = `Collection not found: '${request.path}'. Registered: [${registered}]`;\n logger.error(`[RealtimeService] ${msg}`);\n this.sendError(clientId, msg, subscriptionId);\n return;\n }\n\n // Store subscription in memory with auth context for RLS\n this._subscriptions.set(subscriptionId, {\n clientId,\n type: \"entity\",\n path: request.path,\n entityId: request.entityId,\n authContext\n });\n\n // Send initial data\n const entity = await this.fetchEntityWithAuth(\n request.path,\n String(request.entityId),\n authContext\n );\n\n this.sendEntityUpdate(clientId, subscriptionId, entity || null);\n\n } catch (error) {\n const sanitized = sanitizeErrorForClient(error, request.path);\n this.sendError(clientId, sanitized.message, subscriptionId, sanitized.code);\n }\n }\n\n private async handleUnsubscribe(_clientId: string, subscriptionId: string) {\n this._subscriptions.delete(subscriptionId);\n this.subscriptionCallbacks.delete(subscriptionId);\n // Cancel any pending debounced refetch\n for (const prefix of [\"ws_\", \"drv_\", \"wse_\", \"drve_\"]) {\n const key = `${prefix}${subscriptionId}`;\n const timer = this.refetchTimers.get(key);\n if (timer) { clearTimeout(timer); this.refetchTimers.delete(key); }\n }\n }\n\n /**\n * Enhanced notification method that handles nested relation updates.\n * @param broadcast When true (default), also sends a pg_notify so other instances\n * pick up the change. Set to false when handling an incoming\n * cross-instance notification to avoid infinite loops.\n */\n async notifyEntityUpdate(path: string, entityId: string, entity: Entity | null, databaseId?: string, broadcast = true) {\n this.debugLog(\"🔔 [RealtimeService] notifyEntityUpdate called for path:\", path, \"entityId:\", entityId, \"isDelete:\", entity === null);\n\n // Get all paths that need to be notified - the direct path plus any parent paths\n const pathsToNotify = [path];\n\n // If this is a nested relation path (like \"posts/70/tags\"), also notify parent paths\n if (path.includes(\"/\") && path.split(\"/\").length > 1) {\n const parentPaths = this.getParentPaths(path);\n pathsToNotify.push(...parentPaths);\n this.debugLog(`🔗 [RealtimeService] Nested path detected. Will notify paths: ${pathsToNotify.join(\", \")}`);\n }\n\n // Process each path that needs notification\n for (const notifyPath of pathsToNotify) {\n await this.notifyPathUpdate(notifyPath, path, entityId, entity, databaseId);\n }\n\n // Broadcast to other instances via pg_notify (only for local mutations)\n if (broadcast && this.broadcasting) {\n try {\n await this.broadcastChange(path, entityId, databaseId);\n } catch (err) {\n logger.error(\"❌ [RealtimeService] Failed to broadcast change via pg_notify\", { error: err });\n }\n }\n\n this.debugLog(\"🔔 [RealtimeService] notifyEntityUpdate completed for path:\", path);\n }\n\n /**\n * Notify subscriptions for a specific path\n */\n private async notifyPathUpdate(notifyPath: string, originalPath: string, entityId: string, entity: Entity | null, _databaseId?: string) {\n this.debugLog(`📡 [RealtimeService] Notifying path: ${notifyPath} (original: ${originalPath})`);\n\n // Find all relevant subscriptions for this specific path\n const allSubscriptions = Array.from(this._subscriptions.entries()).filter(([, sub]) => {\n const isPathMatch = sub.path === notifyPath;\n\n // For entity subscriptions, check if the entityId matches (only for exact path matches)\n if (sub.type === \"entity\") {\n return isPathMatch && (notifyPath === originalPath ? sub.entityId === entityId : true);\n }\n // For collection subscriptions, it's always relevant if the path matches\n if (sub.type === \"collection\") {\n return isPathMatch;\n }\n return false;\n });\n\n this.debugLog(`📡 [RealtimeService] Found ${allSubscriptions.length} subscriptions for path: ${notifyPath}`);\n\n // Separate WebSocket subscriptions from DataDriver callback subscriptions\n const webSocketSubscriptions = allSubscriptions.filter(([, sub]) =>\n sub.clientId !== \"driver\" && this.clients.has(sub.clientId)\n );\n\n const driverSubscriptions = allSubscriptions.filter(([subscriptionId, sub]) =>\n sub.clientId === \"driver\" && this.subscriptionCallbacks.has(subscriptionId)\n );\n\n // Handle WebSocket subscriptions\n for (const [subscriptionId, subscription] of webSocketSubscriptions) {\n try {\n if (subscription.type === \"entity\" && notifyPath === originalPath) {\n // Send entity update directly (only for exact path matches)\n if (entity && (entity as unknown as Record<string, unknown>).values && ((entity as unknown as Record<string, unknown>).values as Record<string, unknown>)?._rebase_invalidated) {\n this.debouncedEntityRefetch(subscriptionId, notifyPath, entityId, subscription);\n } else {\n this.sendEntityUpdate(subscription.clientId, subscriptionId, entity);\n }\n } else if (subscription.type === \"collection\" && subscription.collectionRequest) {\n // Phase 1: Send instant entity-level patch (no DB query)\n // This gives immediate cross-tab feedback\n if (!entity || !((entity as unknown as Record<string, unknown>).values && ((entity as unknown as Record<string, unknown>).values as Record<string, unknown>)?._rebase_invalidated)) {\n this.sendCollectionEntityPatch(subscription.clientId, subscriptionId, entityId, entity);\n }\n\n // Phase 2: Schedule a deferred full refetch for correctness\n // Handles filter/sort changes and ensures consistency\n this.debouncedCollectionRefetch(subscriptionId, notifyPath, subscription);\n }\n } catch (error) {\n const sanitized = sanitizeErrorForClient(error, notifyPath);\n this.sendError(subscription.clientId, sanitized.message, subscriptionId, sanitized.code);\n }\n }\n\n // Handle DataDriver callback subscriptions\n for (const [subscriptionId, subscription] of driverSubscriptions) {\n try {\n const callback = this.subscriptionCallbacks.get(subscriptionId);\n if (!callback) continue;\n\n if (subscription.type === \"entity\" && notifyPath === originalPath) {\n if (entity && (entity as unknown as Record<string, unknown>).values && ((entity as unknown as Record<string, unknown>).values as Record<string, unknown>)?._rebase_invalidated) {\n this.debouncedEntityDriverRefetch(subscriptionId, notifyPath, entityId, subscription, callback);\n } else {\n // Call the callback directly with the entity (only for exact path matches)\n callback(entity);\n }\n } else if (subscription.type === \"collection\" && subscription.collectionRequest) {\n // Debounce collection refetches for DataDriver subscriptions too\n this.debouncedDriverRefetch(subscriptionId, notifyPath, subscription, callback);\n }\n } catch (error) {\n logger.error(`❌ [RealtimeService] Error processing DataDriver subscription ${subscriptionId}`, { error: error });\n }\n }\n }\n\n /**\n * Debounce a collection refetch for a WebSocket subscription.\n * Coalesces rapid entity mutations into a single database query.\n */\n private debouncedCollectionRefetch(\n subscriptionId: string,\n notifyPath: string,\n subscription: { clientId: string; collectionRequest?: { filter?: Record<string, unknown>; orderBy?: string; order?: \"desc\" | \"asc\"; limit?: number; offset?: number; startAfter?: Record<string, unknown>; databaseId?: string; searchString?: string }; authContext?: SubscriptionAuthContext }\n ) {\n const timerKey = `ws_${subscriptionId}`;\n const existing = this.refetchTimers.get(timerKey);\n if (existing) clearTimeout(existing);\n\n this.refetchTimers.set(timerKey, setTimeout(async () => {\n this.refetchTimers.delete(timerKey);\n // Verify subscription still exists (client may have disconnected)\n if (!this._subscriptions.has(subscriptionId)) return;\n try {\n const entities = await this.fetchCollectionWithAuth(notifyPath, subscription.collectionRequest!, subscription.authContext);\n this.sendCollectionUpdate(subscription.clientId, subscriptionId, entities);\n } catch (error) {\n const sanitized = sanitizeErrorForClient(error, notifyPath);\n this.sendError(subscription.clientId, sanitized.message, subscriptionId, sanitized.code);\n }\n }, RealtimeService.REFETCH_DEBOUNCE_MS));\n }\n\n /**\n * Debounce a collection refetch for a DataDriver callback subscription.\n */\n private debouncedDriverRefetch(\n subscriptionId: string,\n notifyPath: string,\n subscription: { collectionRequest?: { filter?: Record<string, unknown>; orderBy?: string; order?: \"desc\" | \"asc\"; limit?: number; offset?: number; startAfter?: Record<string, unknown>; databaseId?: string; searchString?: string }; authContext?: SubscriptionAuthContext },\n callback: (data: Entity[] | Entity | null) => void\n ) {\n const timerKey = `drv_${subscriptionId}`;\n const existing = this.refetchTimers.get(timerKey);\n if (existing) clearTimeout(existing);\n\n this.refetchTimers.set(timerKey, setTimeout(async () => {\n this.refetchTimers.delete(timerKey);\n if (!this._subscriptions.has(subscriptionId)) return;\n try {\n const entities = await this.fetchCollectionWithAuth(notifyPath, subscription.collectionRequest!, subscription.authContext);\n callback(entities);\n } catch (error) {\n logger.error(`❌ [RealtimeService] Error in debounced driver refetch for ${subscriptionId}`, { error: error });\n }\n }, RealtimeService.REFETCH_DEBOUNCE_MS));\n }\n\n /**\n * Fetch a collection with optional RLS auth context.\n * When authContext is provided, the fetch runs inside a transaction\n * with set_config calls so PostgreSQL RLS policies are enforced.\n */\n private async fetchCollectionWithAuth(\n notifyPath: string,\n collectionRequest: { filter?: Record<string, unknown>; orderBy?: string; order?: \"desc\" | \"asc\"; limit?: number; offset?: number; startAfter?: Record<string, unknown>; databaseId?: string; searchString?: string },\n authContext?: SubscriptionAuthContext\n ): Promise<Entity[]> {\n if (this.driver) {\n const collection = this.registry.getCollectionByPath(notifyPath);\n const fetchFn = async () => this.driver!.fetchCollection({\n path: notifyPath,\n collection: collection,\n filter: collectionRequest.filter as FetchCollectionProps[\"filter\"],\n orderBy: collectionRequest.orderBy,\n order: collectionRequest.order,\n limit: collectionRequest.limit,\n offset: collectionRequest.offset,\n startAfter: collectionRequest.startAfter,\n searchString: collectionRequest.searchString\n });\n\n // Always wrap in a transaction with session vars, defaulting to anonymous context if missing\n const activeAuth = authContext || { userId: \"anon\",\nroles: [\"anon\"] };\n return await this.db.transaction(async (tx) => {\n await tx.execute(drizzleSql`SELECT set_config('app.user_id', ${activeAuth.userId}, true)`);\n await tx.execute(drizzleSql`SELECT set_config('app.user_roles', ${activeAuth.roles.join(\",\")}, true)`);\n await tx.execute(drizzleSql`SELECT set_config('app.jwt', ${JSON.stringify({ sub: activeAuth.userId,\nroles: activeAuth.roles })}, true)`);\n const txEntityService = new EntityService(tx, this.registry);\n let fetchedEntities;\n if (collectionRequest.searchString) {\n fetchedEntities = await txEntityService.searchEntities(\n notifyPath,\n collectionRequest.searchString,\n {\n filter: collectionRequest.filter as FilterValues<string>,\n orderBy: collectionRequest.orderBy,\n order: collectionRequest.order,\n limit: collectionRequest.limit,\n databaseId: collectionRequest.databaseId\n }\n );\n } else {\n fetchedEntities = await txEntityService.fetchCollection(notifyPath, {\n filter: collectionRequest.filter as FilterValues<string>,\n orderBy: collectionRequest.orderBy,\n order: collectionRequest.order,\n limit: collectionRequest.limit,\n offset: collectionRequest.offset,\n startAfter: collectionRequest.startAfter,\n databaseId: collectionRequest.databaseId\n });\n }\n\n // Re-apply `afterRead` lifecycle hooks to ensure consistent data structures\n // between the initial driver fetch and this RLS-bound refetch.\n const registryCollection = this.registry.getCollectionByPath(notifyPath);\n const resolvedCollection = collection ? { ...collection,\n...registryCollection } as EntityCollection : registryCollection as EntityCollection;\n\n const callbacks = resolvedCollection?.callbacks;\n const propertyCallbacks = resolvedCollection?.properties ? buildPropertyCallbacks(resolvedCollection.properties) : undefined;\n\n if (callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: { uid: activeAuth.userId,\nroles: activeAuth.roles },\n driver: this.driver,\n data: (this.driver && \"data\" in this.driver) ? (this.driver as DataDriverWithData).data : undefined\n } as unknown as RebaseCallContext;\n\n return await Promise.all(fetchedEntities.map(async (entity) => {\n let processedEntity = entity;\n if (callbacks?.afterRead) {\n processedEntity = await callbacks.afterRead({\n collection: resolvedCollection,\n path: notifyPath,\n entity: processedEntity,\n context: contextForCallback\n }) ?? processedEntity;\n }\n if (propertyCallbacks?.afterRead) {\n processedEntity = await propertyCallbacks.afterRead({\n collection: resolvedCollection,\n path: notifyPath,\n entity: processedEntity,\n context: contextForCallback\n }) ?? processedEntity;\n }\n return processedEntity;\n }));\n }\n\n return fetchedEntities;\n });\n }\n\n // No driver — use entityService directly (no auth wrapping possible)\n if (collectionRequest.searchString) {\n return await this.entityService.searchEntities(\n notifyPath,\n collectionRequest.searchString,\n {\n filter: collectionRequest.filter as FilterValues<string>,\n orderBy: collectionRequest.orderBy,\n order: collectionRequest.order,\n limit: collectionRequest.limit,\n databaseId: collectionRequest.databaseId\n }\n );\n }\n return await this.entityService.fetchCollection(notifyPath, {\n filter: collectionRequest.filter as FilterValues<string>,\n orderBy: collectionRequest.orderBy,\n order: collectionRequest.order,\n limit: collectionRequest.limit,\n offset: collectionRequest.offset,\n startAfter: collectionRequest.startAfter,\n databaseId: collectionRequest.databaseId\n });\n }\n\n /**\n * Debounce an entity refetch for a WebSocket subscription.\n */\n private debouncedEntityRefetch(\n subscriptionId: string,\n notifyPath: string,\n entityId: string,\n subscription: { clientId: string; authContext?: SubscriptionAuthContext }\n ) {\n const timerKey = `wse_${subscriptionId}`;\n const existing = this.refetchTimers.get(timerKey);\n if (existing) clearTimeout(existing);\n\n this.refetchTimers.set(timerKey, setTimeout(async () => {\n this.refetchTimers.delete(timerKey);\n if (!this._subscriptions.has(subscriptionId)) return;\n try {\n const entity = await this.fetchEntityWithAuth(notifyPath, entityId, subscription.authContext);\n this.sendEntityUpdate(subscription.clientId, subscriptionId, entity || null);\n } catch (error) {\n const sanitized = sanitizeErrorForClient(error, notifyPath);\n this.sendError(subscription.clientId, sanitized.message, subscriptionId, sanitized.code);\n }\n }, RealtimeService.REFETCH_DEBOUNCE_MS));\n }\n\n /**\n * Debounce an entity refetch for a Driver callback subscription.\n */\n private debouncedEntityDriverRefetch(\n subscriptionId: string,\n notifyPath: string,\n entityId: string,\n subscription: { clientId: string; authContext?: SubscriptionAuthContext },\n callback: (data: Entity[] | Entity | null) => void\n ) {\n const timerKey = `drve_${subscriptionId}`;\n const existing = this.refetchTimers.get(timerKey);\n if (existing) clearTimeout(existing);\n\n this.refetchTimers.set(timerKey, setTimeout(async () => {\n this.refetchTimers.delete(timerKey);\n if (!this._subscriptions.has(subscriptionId)) return;\n try {\n const entity = await this.fetchEntityWithAuth(notifyPath, entityId, subscription.authContext);\n callback(entity || null);\n } catch (error) {\n logger.error(`❌ [RealtimeService] Error in debounced entity driver refetch for ${subscriptionId}`, { error: error });\n }\n }, RealtimeService.REFETCH_DEBOUNCE_MS));\n }\n\n /**\n * Fetch a single entity with optional RLS auth context.\n */\n private async fetchEntityWithAuth(\n notifyPath: string,\n entityId: string | number,\n authContext?: SubscriptionAuthContext\n ): Promise<Entity | undefined> {\n if (this.driver) {\n const collection = this.registry.getCollectionByPath(notifyPath);\n const fetchFn = async () => this.driver!.fetchEntity({\n path: notifyPath,\n entityId,\n collection\n });\n\n // Always wrap in a transaction with session vars, defaulting to anonymous context if missing\n const activeAuth = authContext || { userId: \"anon\",\nroles: [\"anon\"] };\n return await this.db.transaction(async (tx) => {\n await tx.execute(drizzleSql`SELECT set_config('app.user_id', ${activeAuth.userId}, true)`);\n await tx.execute(drizzleSql`SELECT set_config('app.user_roles', ${activeAuth.roles.join(\",\")}, true)`);\n await tx.execute(drizzleSql`SELECT set_config('app.jwt', ${JSON.stringify({ sub: activeAuth.userId,\nroles: activeAuth.roles })}, true)`);\n const txEntityService = new EntityService(tx, this.registry);\n let processedEntity = await txEntityService.fetchEntity(notifyPath, entityId, collection?.databaseId);\n\n if (processedEntity) {\n const registryCollection = this.registry.getCollectionByPath(notifyPath);\n const resolvedCollection = collection ? { ...collection,\n...registryCollection } as EntityCollection : registryCollection as EntityCollection;\n\n const callbacks = resolvedCollection?.callbacks;\n const propertyCallbacks = resolvedCollection?.properties ? buildPropertyCallbacks(resolvedCollection.properties) : undefined;\n\n if (callbacks?.afterRead || propertyCallbacks?.afterRead) {\n const contextForCallback = {\n user: { uid: activeAuth.userId,\nroles: activeAuth.roles },\n driver: this.driver,\n data: (this.driver && \"data\" in this.driver) ? (this.driver as DataDriverWithData).data : undefined\n } as unknown as RebaseCallContext;\n\n if (callbacks?.afterRead) {\n processedEntity = await callbacks.afterRead({\n collection: resolvedCollection,\n path: notifyPath,\n entity: processedEntity,\n context: contextForCallback\n }) ?? processedEntity;\n }\n if (propertyCallbacks?.afterRead) {\n processedEntity = await propertyCallbacks.afterRead({\n collection: resolvedCollection,\n path: notifyPath,\n entity: processedEntity,\n context: contextForCallback\n }) ?? processedEntity;\n }\n }\n }\n\n return processedEntity;\n });\n }\n\n return await this.entityService.fetchEntity(notifyPath, entityId);\n }\n\n private sendCollectionUpdate(clientId: string, subscriptionId: string, entities: Entity[]) {\n const message: CollectionUpdateMessage = {\n type: \"collection_update\",\n subscriptionId,\n entities: entities as Entity<Record<string, unknown>>[]\n };\n this.sendMessage(clientId, message);\n }\n\n private sendEntityUpdate(clientId: string, subscriptionId: string, entity: Entity | null) {\n const message: EntityUpdateMessage = {\n type: \"entity_update\",\n subscriptionId,\n entity: entity as Entity<Record<string, unknown>> | null\n };\n this.sendMessage(clientId, message);\n }\n\n /**\n * Send a lightweight entity-level patch to a collection subscriber.\n * The client can merge this into its cached data for instant feedback.\n */\n private sendCollectionEntityPatch(clientId: string, subscriptionId: string, entityId: string, entity: Entity | null) {\n const message: CollectionEntityPatchMessage = {\n type: \"collection_entity_patch\",\n subscriptionId,\n entityId,\n entity: entity as Entity<Record<string, unknown>> | null\n };\n this.sendMessage(clientId, message);\n }\n\n private sendError(clientId: string, error: string, subscriptionId?: string, code?: string) {\n const message = {\n type: \"error\" as const,\n subscriptionId,\n payload: {\n error: code ? { message: error, code } : error\n },\n error\n };\n this.sendMessage(clientId, message);\n }\n\n private sendMessage(clientId: string, message: CollectionUpdateMessage | EntityUpdateMessage | CollectionEntityPatchMessage | { type: string; subscriptionId?: string; error?: string; payload?: unknown }) {\n const client = this.clients.get(clientId);\n if (client && client.readyState === WebSocket.OPEN) {\n client.send(JSON.stringify(message));\n }\n }\n\n /**\n * Extract parent paths from a nested path like \"posts/70/tags\"\n * Returns [\"posts\", \"posts/70\"] for the example above\n */\n private getParentPaths(path: string): string[] {\n const segments = path.split(\"/\").filter(s => s.length > 0);\n const parentPaths: string[] = [];\n\n // Build parent paths progressively\n for (let i = 1; i < segments.length; i += 2) {\n const parentPath = segments.slice(0, i).join(\"/\");\n if (parentPath) {\n parentPaths.push(parentPath);\n }\n\n // If there's an entity ID, add the path including the entity\n if (i + 1 < segments.length) {\n const pathWithEntity = segments.slice(0, i + 1).join(\"/\");\n parentPaths.push(pathWithEntity);\n }\n }\n\n return parentPaths;\n }\n\n // =============================================================================\n // Broadcast Channels\n // =============================================================================\n\n /** Join a broadcast channel */\n joinChannel(clientId: string, channel: string): void {\n if (!this.channels.has(channel)) {\n this.channels.set(channel, new Set());\n }\n this.channels.get(channel)!.add(clientId);\n this.debugLog(`📡 [Broadcast] Client ${clientId} joined channel: ${channel}`);\n }\n\n /** Leave a broadcast channel */\n leaveChannel(clientId: string, channel: string): void {\n const members = this.channels.get(channel);\n if (members) {\n members.delete(clientId);\n if (members.size === 0) this.channels.delete(channel);\n }\n // Also remove presence\n this.removePresence(clientId, channel);\n }\n\n /** Broadcast a message to all clients in a channel except sender */\n broadcastToChannel(clientId: string, channel: string, event: string, payload: unknown): void {\n const members = this.channels.get(channel);\n if (!members) return;\n\n const message = JSON.stringify({\n type: \"broadcast\",\n channel,\n event,\n payload\n });\n\n for (const memberId of members) {\n if (memberId === clientId) continue; // Don't echo back to sender\n const ws = this.clients.get(memberId);\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(message);\n }\n }\n }\n\n // =============================================================================\n // Presence\n // =============================================================================\n\n /** Track presence in a channel */\n trackPresence(clientId: string, channel: string, state: Record<string, unknown>): void {\n if (!this.presence.has(channel)) {\n this.presence.set(channel, new Map());\n }\n\n const channelPresence = this.presence.get(channel)!;\n channelPresence.set(clientId, { state,\nlastSeen: Date.now() });\n\n // Broadcast join / state update to channel\n this.broadcastPresenceDiff(channel, { [clientId]: state }, {});\n\n // Start cleanup interval if not running\n this.ensurePresenceCleanup();\n }\n\n /** Remove presence from a channel */\n removePresence(clientId: string, channel: string): void {\n const channelPresence = this.presence.get(channel);\n if (!channelPresence) return;\n\n const entry = channelPresence.get(clientId);\n if (entry) {\n channelPresence.delete(clientId);\n this.broadcastPresenceDiff(channel, {}, { [clientId]: entry.state });\n }\n\n if (channelPresence.size === 0) {\n this.presence.delete(channel);\n }\n }\n\n /** Send full presence state to a specific client */\n sendPresenceState(clientId: string, channel: string): void {\n const channelPresence = this.presence.get(channel);\n const presences: Record<string, Record<string, unknown>> = {};\n\n if (channelPresence) {\n for (const [id, { state }] of channelPresence) {\n presences[id] = state;\n }\n }\n\n const ws = this.clients.get(clientId);\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({\n type: \"presence_state\",\n channel,\n presences\n }));\n }\n }\n\n /** Broadcast presence diff (joins/leaves) to channel */\n private broadcastPresenceDiff(\n channel: string,\n joins: Record<string, Record<string, unknown>>,\n leaves: Record<string, Record<string, unknown>>\n ): void {\n const members = this.channels.get(channel);\n if (!members) return;\n\n const message = JSON.stringify({\n type: \"presence_diff\",\n channel,\n joins,\n leaves\n });\n\n for (const memberId of members) {\n const ws = this.clients.get(memberId);\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(message);\n }\n }\n }\n\n /** Periodic cleanup for stale presences */\n private ensurePresenceCleanup(): void {\n if (this.presenceInterval) return;\n this.presenceInterval = setInterval(() => {\n const now = Date.now();\n for (const [channel, channelPresence] of this.presence) {\n for (const [clientId, entry] of channelPresence) {\n if (now - entry.lastSeen > RealtimeService.PRESENCE_TIMEOUT_MS) {\n this.removePresence(clientId, channel);\n }\n }\n }\n // Stop interval if no presences tracked\n if (this.presence.size === 0 && this.presenceInterval) {\n clearInterval(this.presenceInterval);\n this.presenceInterval = undefined;\n }\n }, 10000); // Check every 10s\n }\n\n // =============================================================================\n // Lifecycle / Cleanup\n // =============================================================================\n\n /**\n * Gracefully tear down all realtime resources.\n *\n * This MUST be called during process shutdown, **before** `pool.end()`.\n * It ensures:\n * 1. All debounced refetch timers are cancelled (prevents queries after pool closes).\n * 2. All subscription state and callbacks are cleared.\n * 3. The dedicated LISTEN client (outside the pool) is disconnected.\n * 4. All WebSocket clients are removed (but not forcefully closed — the\n * HTTP server close will handle that).\n */\n async destroy(): Promise<void> {\n // 1. Cancel every pending debounced refetch timer\n for (const [key, timer] of this.refetchTimers) {\n clearTimeout(timer);\n this.refetchTimers.delete(key);\n }\n\n // 2. Clear subscriptions and callbacks\n this._subscriptions.clear();\n this.subscriptionCallbacks.clear();\n\n // 3. Clear broadcast channels and presence\n this.channels.clear();\n this.presence.clear();\n if (this.presenceInterval) {\n clearInterval(this.presenceInterval);\n this.presenceInterval = undefined;\n }\n\n // 4. Disconnect the dedicated LISTEN client\n await this.stopListening();\n\n // 5. Drop client references (don't close — server.close drains them)\n this.clients.clear();\n\n this.debugLog(\"🧹 [RealtimeService] destroy() complete — all resources released.\");\n }\n\n // =============================================================================\n // Cross-Instance LISTEN/NOTIFY\n // =============================================================================\n\n /**\n * Enable cross-instance realtime broadcasting via Postgres LISTEN/NOTIFY.\n * Creates a dedicated pg.Client (outside the Drizzle pool) that stays\n * connected and listens for change notifications from other instances.\n *\n * This is an **optional** feature — if never called, the backend operates\n * in single-instance mode (the default, perfectly fine for most setups).\n *\n * @param connectionString Raw Postgres connection string for the LISTEN client.\n */\n async startListening(connectionString: string): Promise<void> {\n if (this.broadcasting) {\n logger.warn(\"⚠️ [RealtimeService] startListening called but already listening. Ignoring.\");\n return;\n }\n\n this.listenConnectionString = connectionString;\n // Set broadcasting BEFORE connecting so that scheduleReconnect()\n // works correctly if the initial connection attempt fails.\n this.broadcasting = true;\n await this.connectListenClient();\n logger.info(`📡 [RealtimeService] Cross-instance realtime enabled (instanceId: ${this.instanceId})`);\n }\n\n /**\n * Stop listening and clean up the dedicated LISTEN connection.\n */\n async stopListening(): Promise<void> {\n this.broadcasting = false;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.listenClient) {\n try {\n await this.listenClient.end();\n } catch { /* ignore close errors */ }\n this.listenClient = undefined;\n }\n logger.info(\"📡 [RealtimeService] Cross-instance realtime disabled.\");\n }\n\n /**\n * Broadcast a change notification to other instances via pg_notify.\n * Uses the main Drizzle connection (pooled) — NOT the LISTEN client.\n */\n private async broadcastChange(path: string, entityId: string, databaseId?: string): Promise<void> {\n const payload = JSON.stringify({\n sid: this.instanceId,\n p: path,\n eid: entityId,\n db: databaseId ?? null\n });\n await this.db.execute(drizzleSql`SELECT pg_notify(${PG_NOTIFY_CHANNEL}, ${payload})`);\n }\n\n /**\n * Create and connect the dedicated LISTEN client with auto-reconnect.\n */\n private async connectListenClient(): Promise<void> {\n if (!this.listenConnectionString) return;\n\n try {\n const client = new PgClient({ connectionString: this.listenConnectionString });\n\n client.on(\"error\", (err) => {\n logger.error(\"❌ [RealtimeService] LISTEN client error\", { detail: err.message });\n this.scheduleReconnect();\n });\n\n client.on(\"end\", () => {\n if (this.broadcasting) {\n logger.warn(\"⚠️ [RealtimeService] LISTEN client disconnected unexpectedly.\");\n this.scheduleReconnect();\n }\n });\n\n client.on(\"notification\", async (msg) => {\n if (!msg.payload) return;\n try {\n const { sid, p, eid, db } = JSON.parse(msg.payload) as {\n sid: string;\n p: string;\n eid: string;\n db: string | null;\n };\n\n // Skip our own notifications — already processed locally\n if (sid === this.instanceId) return;\n\n this.debugLog(`📡 [RealtimeService] Received cross-instance notification: path=${p}, entityId=${eid}, from=${sid}`);\n\n // Refetch the entity from the DB so entity subscriptions\n // receive the actual data instead of null (which the client\n // would interpret as \"deleted\").\n let entity: Entity | null = null;\n try {\n if (this.driver) {\n const collection = this.registry.getCollectionByPath(p);\n const fetched = await this.driver.fetchEntity({\n path: p,\n entityId: eid,\n collection: collection\n });\n entity = fetched ?? null;\n } else {\n const fetched = await this.entityService.fetchEntity(\n p, eid, db ?? undefined\n );\n entity = fetched ?? null;\n }\n } catch (fetchErr) {\n // If the fetch fails (e.g. entity was deleted), entity stays null\n this.debugLog(`📡 [RealtimeService] Could not refetch entity ${eid} from ${p} — treating as deleted`, fetchErr);\n }\n\n // Trigger local fan-out with broadcast=false to avoid re-broadcasting\n await this.notifyEntityUpdate(p, eid, entity, db ?? undefined, false);\n } catch (err) {\n logger.error(\"❌ [RealtimeService] Error processing cross-instance notification\", { error: err });\n }\n });\n\n await client.connect();\n await client.query(`LISTEN ${PG_NOTIFY_CHANNEL}`);\n this.listenClient = client;\n\n this.debugLog(`📡 [RealtimeService] LISTEN client connected on channel \"${PG_NOTIFY_CHANNEL}\"`);\n } catch (err) {\n logger.error(\"❌ [RealtimeService] Failed to connect LISTEN client\", { error: err });\n this.scheduleReconnect();\n }\n }\n\n /**\n * Schedule a reconnection attempt with a fixed 3s delay.\n */\n private scheduleReconnect(): void {\n if (!this.broadcasting || this.reconnectTimer) return;\n\n const delay = 3000; // Fixed 3s delay; simple and predictable\n this.debugLog(`📡 [RealtimeService] Scheduling LISTEN reconnect in ${delay}ms...`);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = undefined;\n if (!this.broadcasting) return;\n\n // Clean up old client\n if (this.listenClient) {\n try { await this.listenClient.end(); } catch { /* ignore */ }\n this.listenClient = undefined;\n }\n\n await this.connectListenClient();\n }, delay);\n }\n}\n\n/**\n * Alias for RealtimeService for consistent naming with other database implementations.\n * This allows code to use PostgresRealtimeProvider alongside future MongoRealtimeProvider, etc.\n */\nexport const PostgresRealtimeProvider = RealtimeService;\n","import { RealtimeService } from \"./services/realtimeService\";\nimport { PostgresBackendDriver } from \"./PostgresBackendDriver\";\nimport type { DataDriver, DeleteEntityProps, FetchCollectionProps, FetchEntityProps, SaveEntityProps, TableMetadata, BranchInfo, AuthAdapter } from \"@rebasepro/types\";\nimport { isSQLAdmin, isSchemaAdmin } from \"@rebasepro/types\";\nimport type { User } from \"@rebasepro/types\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport { Server } from \"http\";\nimport { inspect } from \"util\";\nimport { extractUserFromToken, AccessTokenPayload } from \"@rebasepro/server-core\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/** Minimal subset of RebaseAuthConfig used by the WebSocket layer. */\ninterface WsAuthConfig {\n requireAuth?: boolean;\n jwtSecret?: string;\n}\n\n/**\n * Normalized user identity for WebSocket sessions.\n */\ninterface WsUserIdentity {\n userId: string;\n roles: string[];\n isAdmin: boolean;\n}\n\ninterface ClientSession {\n ws: WebSocket;\n user?: WsUserIdentity;\n authenticated: boolean;\n /** Sliding window message counter for rate limiting */\n messageCount: number;\n messageWindowStart: number;\n}\n\n\n/** Maximum messages per client per window */\nconst WS_RATE_LIMIT = 2000;\n/** Rate limit window in milliseconds (60 seconds) */\nconst WS_RATE_WINDOW_MS = 60_000;\n\n/** Admin-only WebSocket message types */\nconst ADMIN_ONLY_TYPES = new Set([\n \"EXECUTE_SQL\",\n \"FETCH_DATABASES\",\n \"FETCH_ROLES\",\n \"FETCH_UNMAPPED_TABLES\",\n \"FETCH_TABLE_METADATA\",\n \"FETCH_CURRENT_DATABASE\",\n \"CREATE_BRANCH\",\n \"DELETE_BRANCH\",\n \"LIST_BRANCHES\"\n]);\n\n/**\n * Recursively extract the deepest error message from an error's cause chain (e.g., Drizzle wrapping a PG error).\n */\nfunction extractErrorMessage(error: unknown): string {\n if (!error) return \"Unknown error\";\n if (error instanceof Error) {\n if (\"cause\" in error && error.cause) {\n return extractErrorMessage(error.cause);\n }\n return error.message;\n }\n if (typeof error === \"object\" && \"message\" in error && typeof (error as { message: unknown }).message === \"string\") {\n return (error as { message: string }).message;\n }\n return String(error);\n}\n\n/**\n * Check if the current session belongs to an admin user.\n */\nfunction isAdminSession(session: ClientSession | undefined): boolean {\n if (!session?.user) return false;\n // Fast path: new adapter-aware sessions set isAdmin directly\n if (session.user.isAdmin) return true;\n if (!session.user.roles) return false;\n return session.user.roles.some((r) => r === \"admin\");\n}\n\nexport function createPostgresWebSocket(\n server: Server,\n realtimeService: RealtimeService,\n driver: PostgresBackendDriver,\n authConfig?: WsAuthConfig,\n authAdapter?: AuthAdapter\n) {\n // Session map scoped to this factory invocation — prevents stale sessions\n // leaking across hot reloads or multiple factory calls.\n const clientSessions = new Map<string, ClientSession>();\n\n const isProduction = process.env.NODE_ENV === \"production\";\n /** Debug logger that is suppressed in production to prevent PII/data leaks */\n const wsDebug = (...args: unknown[]) => { if (!isProduction) console.debug(...args); };\n const wss = new WebSocketServer({ server });\n\n // Handle errors on the WSS so that EADDRINUSE from the underlying HTTP\n // server doesn't surface as an unhandled 'error' event and crash the\n // process. The dev-mode `listenWithPortRetry` utility handles retry\n // logic on the HTTP server side — we just need the WSS not to throw.\n wss.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Silently absorbed — listenWithPortRetry will retry the next port\n return;\n }\n logger.error(\"❌ [WebSocket Server] Error\", { error: err });\n });\n\n // Auth is required when either: an adapter is present (secure by default),\n // OR the config has a jwtSecret and requireAuth !== false.\n const requireAuth = authAdapter\n ? true\n : (authConfig?.requireAuth !== false && !!authConfig?.jwtSecret);\n\n wss.on(\"connection\", (ws) => {\n const clientId = `client_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n wsDebug(`WebSocket client connected: ${clientId}`);\n\n // Initialize client session\n clientSessions.set(clientId, { ws,\nauthenticated: !requireAuth,\nmessageCount: 0,\nmessageWindowStart: Date.now() });\n realtimeService.addClient(clientId, ws);\n\n ws.on(\"close\", () => {\n wsDebug(`WebSocket client disconnected: ${clientId}`);\n clientSessions.delete(clientId);\n });\n\n // Route all messages through RealtimeService for unified handling\n ws.on(\"message\", async (message) => {\n let requestId: string | undefined;\n try {\n const {\n type,\n payload,\n requestId: reqId\n } = JSON.parse(message.toString());\n requestId = reqId; // Capture requestId for use in catch block\n\n wsDebug(`[WS] ${clientId} → ${type}`, requestId ? `(${requestId})` : \"\");\n\n // Handle authentication first\n // Helper: send a canonical error frame\n const sendError = (errType: \"ERROR\" | \"AUTH_ERROR\", code: string, msg: string) => {\n ws.send(JSON.stringify({\n type: errType,\n requestId,\n payload: { error: { message: msg,\ncode } }\n }));\n };\n\n if (type === \"AUTHENTICATE\") {\n const { token } = payload || {};\n if (!token) {\n sendError(\"AUTH_ERROR\", \"INVALID_INPUT\", \"Token is required\");\n return;\n }\n\n // Use the auth adapter when available (custom auth, Clerk, etc.)\n // Fall back to JWT extraction otherwise.\n let verifiedUser: WsUserIdentity | null = null;\n\n if (authAdapter) {\n try {\n const adapterUser = authAdapter.verifyToken\n ? await authAdapter.verifyToken(token)\n : await authAdapter.verifyRequest(new Request(\"http://localhost/_ws_auth\", {\n headers: { Authorization: `Bearer ${token}` }\n }));\n\n if (adapterUser) {\n verifiedUser = {\n userId: adapterUser.uid,\n roles: adapterUser.roles,\n isAdmin: adapterUser.isAdmin\n };\n }\n } catch {\n // Adapter threw — treat as invalid token\n }\n } else {\n // Standard JWT path\n const jwtPayload = extractUserFromToken(token);\n if (jwtPayload) {\n verifiedUser = {\n userId: jwtPayload.userId,\n roles: jwtPayload.roles ?? [],\n isAdmin: (jwtPayload.roles ?? []).some((r: string) => r === \"admin\")\n };\n }\n }\n\n if (verifiedUser) {\n const session = clientSessions.get(clientId);\n if (session) {\n session.user = verifiedUser;\n session.authenticated = true;\n }\n wsDebug(`[WS] replying AUTH_SUCCESS for requestId ${requestId}`);\n ws.send(JSON.stringify({\n type: \"AUTH_SUCCESS\",\n requestId,\n payload: { userId: verifiedUser.userId,\nroles: verifiedUser.roles }\n }));\n wsDebug(`🔐 [WebSocket Server] Client ${clientId} authenticated as ${verifiedUser.userId}`);\n } else {\n wsDebug(`[WS] replying AUTH_ERROR for requestId ${requestId} (invalid token)`);\n sendError(\"AUTH_ERROR\", \"INVALID_TOKEN\", \"Invalid or expired token\");\n }\n return;\n }\n\n // Check authentication for protected operations\n if (requireAuth) {\n const session = clientSessions.get(clientId);\n if (!session?.authenticated) {\n sendError(\"ERROR\", \"UNAUTHORIZED\", \"Authentication required\");\n return;\n }\n }\n\n // Rate limiting: reject if client exceeds message limit\n {\n const session = clientSessions.get(clientId);\n if (session) {\n const now = Date.now();\n if (now - session.messageWindowStart > WS_RATE_WINDOW_MS) {\n session.messageCount = 0;\n session.messageWindowStart = now;\n }\n session.messageCount++;\n if (session.messageCount > WS_RATE_LIMIT) {\n sendError(\"ERROR\", \"RATE_LIMITED\", \"Too many requests. Please slow down.\");\n return;\n }\n }\n }\n\n // Admin-only operations require admin role\n if (ADMIN_ONLY_TYPES.has(type)) {\n const session = clientSessions.get(clientId);\n if (!isAdminSession(session)) {\n sendError(\"ERROR\", \"FORBIDDEN\", \"Admin access required for this operation\");\n return;\n }\n }\n\n // Helper to get correctly scoped delegate for the current request\n const getScopedDelegate = async (): Promise<DataDriver> => {\n const session = clientSessions.get(clientId);\n // Check if the driver supports RLS-scoped delegates\n if (typeof driver.withAuth === \"function\") {\n try {\n const userForAuth: User = session?.user\n ? {\n uid: session.user.userId,\n displayName: null,\n email: null,\n photoURL: null,\n providerId: \"websocket\",\n isAnonymous: false,\n roles: session.user.roles ?? []\n }\n : {\n uid: \"anon\",\n displayName: null,\n email: null,\n photoURL: null,\n providerId: \"websocket\",\n isAnonymous: true,\n roles: [\"anon\"]\n };\n return await driver.withAuth(userForAuth);\n } catch (e) {\n logger.error(\"Failed to create RLS scoped delegate for WS request\", { error: e });\n throw new Error(\"Internal authentication error\");\n }\n }\n return driver;\n };\n\n switch (type) {\n case \"FETCH_COLLECTION\": {\n wsDebug(\"📋 [WebSocket Server] Processing FETCH_COLLECTION request\");\n const request: FetchCollectionProps = payload;\n const delegate = await getScopedDelegate();\n const entities = await delegate.fetchCollection(request);\n wsDebug(\"📋 [WebSocket Server] FETCH_COLLECTION result - entities count:\", entities.length);\n const response = {\n type: \"FETCH_COLLECTION_SUCCESS\",\n payload: { entities },\n requestId\n };\n wsDebug(\"📋 [WebSocket Server] Sending FETCH_COLLECTION_SUCCESS response\");\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"FETCH_ENTITY\": {\n wsDebug(\"📄 [WebSocket Server] Processing FETCH_ENTITY request\");\n const request: FetchEntityProps = payload;\n const delegate = await getScopedDelegate();\n const entity = await delegate.fetchEntity(request);\n wsDebug(\"📄 [WebSocket Server] FETCH_ENTITY result:\", entity);\n const response = {\n type: \"FETCH_ENTITY_SUCCESS\",\n payload: { entity },\n requestId\n };\n wsDebug(\"📄 [WebSocket Server] Sending FETCH_ENTITY_SUCCESS response\");\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"SAVE_ENTITY\": {\n wsDebug(\"💾 [WebSocket Server] Processing SAVE_ENTITY request\");\n const request: SaveEntityProps = payload;\n wsDebug(\"💾 [WebSocket Server] Saving entity with request:\", inspect(request, { depth: null,\ncolors: true }));\n const delegate = await getScopedDelegate();\n const entity = await delegate.saveEntity(request);\n wsDebug(\"💾 [WebSocket Server] SAVE_ENTITY result:\", inspect(entity, { depth: null,\ncolors: true }));\n const response = {\n type: \"SAVE_ENTITY_SUCCESS\",\n payload: { entity },\n requestId\n };\n wsDebug(\"💾 [WebSocket Server] Sending SAVE_ENTITY_SUCCESS response\");\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"DELETE_ENTITY\": {\n wsDebug(\"🗑️ [WebSocket Server] Processing DELETE_ENTITY request\");\n const request: DeleteEntityProps = payload;\n wsDebug(\"🗑️ [WebSocket Server] Deleting entity:\", request.entity);\n const delegate = await getScopedDelegate();\n await delegate.deleteEntity(request);\n wsDebug(\"🗑️ [WebSocket Server] DELETE_ENTITY completed successfully\");\n const response = {\n type: \"DELETE_ENTITY_SUCCESS\",\n payload: { success: true },\n requestId\n };\n wsDebug(\"🗑️ [WebSocket Server] Sending DELETE_ENTITY_SUCCESS response\");\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"CHECK_UNIQUE_FIELD\": {\n wsDebug(\"🔍 [WebSocket Server] Processing CHECK_UNIQUE_FIELD request\");\n const {\n path,\n name,\n value,\n entityId,\n collection\n } = payload;\n const delegate = await getScopedDelegate();\n const isUnique = await delegate.checkUniqueField(path, name, value, entityId, collection);\n wsDebug(\"🔍 [WebSocket Server] CHECK_UNIQUE_FIELD result:\", isUnique);\n const response = {\n type: \"CHECK_UNIQUE_FIELD_SUCCESS\",\n payload: { isUnique },\n requestId\n };\n wsDebug(\"🔍 [WebSocket Server] Sending CHECK_UNIQUE_FIELD_SUCCESS response\");\n ws.send(JSON.stringify(response));\n }\n break;\n\n\n case \"COUNT_ENTITIES\": {\n const request: FetchCollectionProps = payload;\n const delegate = await getScopedDelegate();\n const count = await delegate.countEntities!(request);\n const response = {\n type: \"COUNT_ENTITIES_SUCCESS\",\n payload: { count },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"EXECUTE_SQL\": {\n const { sql, options } = payload;\n try {\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n if (!isSQLAdmin(admin)) {\n sendError(\"ERROR\", \"NOT_SUPPORTED\", \"SQL execution is not available for this driver.\");\n break;\n }\n const result = await admin.executeSql(sql, options);\n if (process.env.NODE_ENV !== \"production\") {\n wsDebug(`⚡ [WebSocket Server] SQL executed. Returned ${Array.isArray(result) ? result.length : \"non-array\"} rows.`);\n }\n const response = {\n type: \"EXECUTE_SQL_SUCCESS\",\n payload: { result },\n requestId\n };\n ws.send(JSON.stringify(response));\n } catch (sqlError: unknown) {\n // This is a query execution error (e.g., syntax error, permission denied).\n // We return it cleanly to the client without logging a server stack trace.\n const errMsg = extractErrorMessage(sqlError);\n sendError(\"ERROR\", \"SQL_ERROR\", errMsg);\n }\n }\n break;\n\n case \"FETCH_DATABASES\": {\n wsDebug(\"📚 [WebSocket Server] Processing FETCH_DATABASES request\");\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n let databases: string[] = [];\n if (isSQLAdmin(admin) && admin.fetchAvailableDatabases) {\n databases = await admin.fetchAvailableDatabases();\n }\n wsDebug(`📚 [WebSocket Server] Fetched ${databases.length} databases.`);\n const response = {\n type: \"FETCH_DATABASES_SUCCESS\",\n payload: { databases },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"FETCH_ROLES\": {\n wsDebug(\"👤 [WebSocket Server] Processing FETCH_ROLES request\");\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n let roles: string[] = [];\n if (isSQLAdmin(admin) && admin.fetchAvailableRoles) {\n roles = await admin.fetchAvailableRoles();\n }\n wsDebug(`👤 [WebSocket Server] Fetched ${roles.length} roles.`);\n const response = {\n type: \"FETCH_ROLES_SUCCESS\",\n payload: { roles },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"FETCH_CURRENT_DATABASE\": {\n wsDebug(\"📚 [WebSocket Server] Processing FETCH_CURRENT_DATABASE request\");\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n let database: string | undefined = undefined;\n if (isSQLAdmin(admin) && admin.fetchCurrentDatabase) {\n database = await admin.fetchCurrentDatabase();\n }\n const response = {\n type: \"FETCH_CURRENT_DATABASE_SUCCESS\",\n payload: { database },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"FETCH_UNMAPPED_TABLES\": {\n wsDebug(\"📋 [WebSocket Server] Processing FETCH_UNMAPPED_TABLES request\");\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n let tables: string[] = [];\n if (isSchemaAdmin(admin) && admin.fetchUnmappedTables) {\n tables = await admin.fetchUnmappedTables(payload?.mappedPaths);\n }\n wsDebug(`📋 [WebSocket Server] Fetched ${tables.length} unmapped tables.`);\n const response = {\n type: \"FETCH_UNMAPPED_TABLES_SUCCESS\",\n payload: { tables },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"FETCH_TABLE_METADATA\": {\n wsDebug(\"📋 [WebSocket Server] Processing FETCH_TABLE_METADATA request\");\n const { tableName } = payload;\n const delegate = await getScopedDelegate();\n const admin = delegate.admin;\n let metadata: TableMetadata | undefined;\n if (isSchemaAdmin(admin) && admin.fetchTableMetadata) {\n metadata = await admin.fetchTableMetadata(tableName) as TableMetadata;\n }\n wsDebug(`📋 [WebSocket Server] Fetched metadata for table '${tableName}'. (${metadata?.columns?.length ?? 0} columns)`);\n const response = {\n type: \"FETCH_TABLE_METADATA_SUCCESS\",\n payload: { metadata },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"CREATE_BRANCH\": {\n wsDebug(\"🌿 [WebSocket Server] Processing CREATE_BRANCH request\");\n const { name, options } = payload;\n const delegate = await getScopedDelegate();\n if (!delegate.admin?.createBranch) {\n sendError(\"ERROR\", \"NOT_SUPPORTED\", \"Database branching is not available. Configure adminConnectionString.\");\n break;\n }\n const branch: BranchInfo = await delegate.admin.createBranch(name, options);\n wsDebug(`🌿 [WebSocket Server] Branch created: ${branch.name}`);\n const response = {\n type: \"CREATE_BRANCH_SUCCESS\",\n payload: { branch },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"DELETE_BRANCH\": {\n wsDebug(\"🗑️ [WebSocket Server] Processing DELETE_BRANCH request\");\n const { name: branchName } = payload;\n const delegate = await getScopedDelegate();\n if (!delegate.admin?.deleteBranch) {\n sendError(\"ERROR\", \"NOT_SUPPORTED\", \"Database branching is not available.\");\n break;\n }\n await delegate.admin.deleteBranch(branchName);\n wsDebug(`🗑️ [WebSocket Server] Branch deleted: ${branchName}`);\n const response = {\n type: \"DELETE_BRANCH_SUCCESS\",\n payload: { success: true },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n case \"LIST_BRANCHES\": {\n wsDebug(\"🌿 [WebSocket Server] Processing LIST_BRANCHES request\");\n const delegate = await getScopedDelegate();\n let branches: BranchInfo[] = [];\n if (delegate.admin?.listBranches) {\n branches = await delegate.admin.listBranches();\n }\n wsDebug(`🌿 [WebSocket Server] Listed ${branches.length} branches.`);\n const response = {\n type: \"LIST_BRANCHES_SUCCESS\",\n payload: { branches },\n requestId\n };\n ws.send(JSON.stringify(response));\n }\n break;\n\n // Route subscription messages, broadcast channels, and presence to RealtimeService\n case \"subscribe_collection\":\n case \"subscribe_entity\":\n case \"unsubscribe\":\n case \"join_channel\":\n case \"leave_channel\":\n case \"broadcast\":\n case \"presence_track\":\n case \"presence_untrack\":\n case \"presence_state\": {\n wsDebug(\"🔄 [WebSocket Server] Routing realtime message to RealtimeService:\", type);\n // Attach auth context from the WS session so RLS-aware refetches work\n const session = clientSessions.get(clientId);\n const authContext = session?.user\n ? { userId: session.user.userId,\nroles: session.user.roles ?? [] }\n : { userId: \"anon\",\nroles: [\"anon\"] };\n // Let RealtimeService handle these messages\n await realtimeService.handleClientMessage(clientId, {\n type,\n payload,\n subscriptionId: payload?.subscriptionId\n }, authContext);\n break;\n }\n\n default:\n logger.error(\"❌ [WebSocket Server] Unknown message type\", { detail: type });\n }\n } catch (error: unknown) {\n logger.error(\"💥 [WebSocket Server] Error handling message\", { error: error });\n if (error instanceof Error) {\n logger.error(\"Stack trace\", { detail: error.stack });\n }\n const errorMessage = process.env.NODE_ENV === \"production\"\n ? \"An unexpected error occurred\"\n : (error instanceof Error ? error.message : \"An unexpected error occurred\");\n const errorResponse = {\n type: \"ERROR\",\n requestId,\n payload: {\n error: {\n message: errorMessage,\n code: \"INTERNAL_ERROR\"\n }\n }\n };\n ws.send(JSON.stringify(errorResponse));\n }\n });\n });\n}\n","import { CollectionRegistry } from \"@rebasepro/common\";\nimport { type CollectionWithRelations, type EntityCollection, type Relation, getDataSourceCapabilities } from \"@rebasepro/types\";\nimport { PgEnum, PgTable } from \"drizzle-orm/pg-core\";\nimport { Relations } from \"drizzle-orm\";\nimport { CollectionRegistryInterface } from \"../interfaces\";\nimport { getTableName } from \"@rebasepro/common\";\n\n/**\n * PostgreSQL-specific collection registry.\n * Extends the base CollectionRegistry with support for Drizzle ORM tables, enums, and relations.\n *\n * Satisfies CollectionRegistryInterface through inheritance from CollectionRegistry.\n */\nexport class PostgresCollectionRegistry extends CollectionRegistry implements CollectionRegistryInterface {\n\n private tables = new Map<string, PgTable>();\n private enums = new Map<string, PgEnum<[string, ...string[]]>>();\n private relations = new Map<string, Relations>();\n\n registerTable(table: PgTable, tableName: string) {\n this.tables.set(tableName, table);\n }\n\n getTable(tableName: string): PgTable | undefined {\n return this.tables.get(tableName);\n }\n\n /**\n * Checks if a specific collection has a registered table\n */\n hasTableForCollection(tableName: string): boolean {\n return this.tables.has(tableName);\n }\n\n /**\n * Returns all registered table names.\n */\n getTableNames(): string[] {\n return Array.from(this.tables.keys());\n }\n\n /**\n * Finds collections assigned to a specific driver that do not have a registered table.\n */\n getCollectionsWithoutTables(driverId = \"(default)\"): EntityCollection[] {\n const collections = this.getCollections().filter(\n c => c.driver === driverId || (!c.driver && driverId === \"(default)\")\n );\n return collections.filter(c => !this.tables.has(getTableName(c)));\n }\n\n registerEnums(enums: Record<string, PgEnum<[string, ...string[]]>>) {\n Object.entries(enums).forEach(([name, value]) => this.enums.set(name, value));\n }\n\n registerRelations(relations: Record<string, Relations>) {\n Object.entries(relations).forEach(([name, value]) => this.relations.set(name, value));\n }\n\n getEnum(name: string): PgEnum<[string, ...string[]]> | undefined {\n return this.enums.get(name);\n }\n\n getRelation(name: string): Relations | undefined {\n return this.relations.get(name);\n }\n\n getAllEnums(): Record<string, PgEnum<[string, ...string[]]>> {\n return Object.fromEntries(this.enums.entries());\n }\n\n getAllRelations(): Record<string, Relations> {\n return Object.fromEntries(this.relations.entries());\n }\n\n /**\n * Get the merged schema object (tables + relations) for use with Drizzle's\n * relational query API (`db.query`).\n */\n getMergedSchema(): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [name, table] of this.tables.entries()) {\n result[name] = table;\n }\n for (const [name, relation] of this.relations.entries()) {\n result[name] = relation;\n }\n return result;\n }\n\n /**\n * Get the available Drizzle relation keys for a given collection path.\n * Maps from the collection's relation property names to the Drizzle relation names\n * defined in the schema.\n */\n getRelationKeysForCollection(collectionPath: string): string[] {\n const collection = this.getCollectionByPath(collectionPath);\n if (!collection || !getDataSourceCapabilities(collection.driver).supportsRelations || !(collection as CollectionWithRelations).relations) return [];\n return (collection as CollectionWithRelations).relations!.map((r: Relation) => r.relationName || r.localKey || \"\").filter(Boolean);\n }\n\n}\n\n","import { sql } from \"drizzle-orm\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { logger } from \"@rebasepro/server-core\";\nimport type { EntityCollection } from \"@rebasepro/types\";\n\n\n/**\n * Auto-create auth tables if they don't exist.\n *\n * @param db — Drizzle database instance\n * @param collection — The collection that represents auth users.\n * When omitted, a default `rebase.users` table is created.\n */\nexport async function ensureAuthTablesExist(db: NodePgDatabase, collection?: EntityCollection): Promise<void> {\n logger.info(\"🔍 Checking auth tables...\");\n\n try {\n // Resolve dynamic user table name and ID type from the collection\n let usersTableName = '\"rebase\".\"users\"';\n let userIdType = \"TEXT\";\n let usersSchema = \"rebase\";\n let resolvedTable = \"users\";\n if (collection) {\n resolvedTable = (\"table\" in collection && typeof collection.table === \"string\")\n ? collection.table\n : collection.slug;\n usersSchema = (\"schema\" in collection && typeof collection.schema === \"string\")\n ? collection.schema\n : \"public\";\n usersTableName = usersSchema === \"public\"\n ? `\"${resolvedTable}\"`\n : `\"${usersSchema}\".\"${resolvedTable}\"`;\n\n // Derive ID column type from collection properties\n const idProp = collection.properties?.id;\n if (idProp) {\n const isId = (\"isId\" in idProp) ? (idProp as unknown as Record<string, unknown>).isId : undefined;\n if (isId === \"uuid\") {\n userIdType = \"UUID\";\n } else if (isId === \"autoincrement\") {\n userIdType = \"INTEGER\";\n }\n // Otherwise keep TEXT as default\n }\n }\n\n // Introspect the database to find the actual type of usersTableName's ID column if the table exists\n try {\n const result = await db.execute(sql`\n SELECT data_type \n FROM information_schema.columns \n WHERE table_schema = ${usersSchema} \n AND table_name = ${resolvedTable} \n AND column_name = 'id'\n `);\n if (result && result.rows && result.rows.length > 0) {\n const dbType = String((result.rows[0] as { data_type: string }).data_type).toUpperCase();\n if (dbType === \"UUID\") {\n userIdType = \"UUID\";\n } else if (dbType === \"INTEGER\" || dbType === \"SMALLINT\" || dbType === \"BIGINT\") {\n userIdType = \"INTEGER\";\n } else {\n userIdType = \"TEXT\";\n }\n logger.info(`✨ Detected ${usersTableName}.id type from database: ${dbType}. Using user_id type: ${userIdType}`);\n }\n } catch (err) {\n // Ignore introspection errors, fallback to derived/default type\n logger.warn(`⚠️ Failed to introspect ${usersTableName}.id type from database, falling back to config type: ${userIdType}`, { error: err });\n }\n\n\n // ── Create schemas (idempotent) ──────────────────────────────────\n if (usersSchema !== \"public\") {\n await db.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sql.raw(usersSchema)}`);\n }\n await db.execute(sql`CREATE SCHEMA IF NOT EXISTS rebase`);\n\n const authSchema = usersSchema === \"public\" ? \"rebase\" : usersSchema;\n const userIdentitiesTable = `\"${authSchema}\".\"user_identities\"`;\n const refreshTokensTableName = `\"${authSchema}\".\"refresh_tokens\"`;\n const passwordResetTokensTableName = `\"${authSchema}\".\"password_reset_tokens\"`;\n const appConfigTableName = `\"${authSchema}\".\"app_config\"`;\n\n // ── Create tables (idempotent) ──────────────────────────────────\n\n // Create user_identities table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(userIdentitiesTable)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,\n provider TEXT NOT NULL,\n provider_id TEXT NOT NULL,\n profile_data JSONB,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n UNIQUE(provider, provider_id)\n )\n `);\n\n // Create indexes on user_identities\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_user_identities_user \n ON ${sql.raw(userIdentitiesTable)}(user_id)\n `);\n\n\n // Create refresh tokens table (includes user_agent, ip_address, and unique constraint)\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(refreshTokensTableName)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n user_agent TEXT,\n ip_address TEXT,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n CONSTRAINT unique_device_session UNIQUE (user_id, user_agent, ip_address)\n )\n `);\n\n // Create index on token_hash for faster lookups\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_refresh_tokens_hash \n ON ${sql.raw(refreshTokensTableName)}(token_hash)\n `);\n\n // Create index on user_id for cleanup operations\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user \n ON ${sql.raw(refreshTokensTableName)}(user_id)\n `);\n\n // Create password reset tokens table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(passwordResetTokensTableName)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,\n token_hash TEXT NOT NULL UNIQUE,\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL,\n used_at TIMESTAMP WITH TIME ZONE,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `);\n\n // Create index on token_hash for password reset lookups\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_hash \n ON ${sql.raw(passwordResetTokensTableName)}(token_hash)\n `);\n\n // Create index on user_id for password reset cleanup\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_password_reset_tokens_user \n ON ${sql.raw(passwordResetTokensTableName)}(user_id)\n `);\n\n // Create app config table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(appConfigTableName)} (\n key TEXT PRIMARY KEY,\n value JSONB NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `);\n\n // Create the `auth` schema with Supabase-style helper functions for RLS.\n await db.execute(sql`CREATE SCHEMA IF NOT EXISTS auth`);\n\n // Use an advisory transaction lock to serialize function recreation during HMR\n await db.transaction(async (tx) => {\n await tx.execute(sql`SELECT pg_advisory_xact_lock(hashtext('rebase_auth_functions_init'))`);\n\n await tx.execute(sql`\n CREATE OR REPLACE FUNCTION auth.uid() RETURNS text AS $$\n SELECT NULLIF(current_setting('app.user_id', true), '');\n $$ LANGUAGE sql STABLE\n `);\n\n await tx.execute(sql`\n CREATE OR REPLACE FUNCTION auth.jwt() RETURNS jsonb AS $$\n SELECT COALESCE(\n NULLIF(current_setting('app.jwt', true), ''),\n '{}'\n )::jsonb;\n $$ LANGUAGE sql STABLE\n `);\n\n await tx.execute(sql`\n CREATE OR REPLACE FUNCTION auth.roles() RETURNS text AS $$\n SELECT COALESCE(NULLIF(current_setting('app.user_roles', true), ''), '');\n $$ LANGUAGE sql STABLE\n `);\n });\n\n // Seed default roles if none exist\n // (no-op: roles are now stored inline on the users table)\n\n // ── Migration: Add is_anonymous column (safe for existing tables) ────\n await db.execute(sql`\n ALTER TABLE ${sql.raw(usersTableName)}\n ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN DEFAULT FALSE\n `);\n\n // ── Migration: Add inline roles column (safe for existing tables) ────\n await db.execute(sql`\n ALTER TABLE ${sql.raw(usersTableName)}\n ADD COLUMN IF NOT EXISTS roles TEXT[] DEFAULT '{}' NOT NULL\n `);\n\n // ── Migration: Copy roles from legacy junction table to inline column ──\n // If the old rebase.user_roles and rebase.roles tables exist, migrate\n // the data into the new TEXT[] column then drop the legacy tables.\n try {\n const legacyCheck = await db.execute(sql`\n SELECT EXISTS (\n SELECT 1 FROM information_schema.tables\n WHERE table_schema = 'rebase' AND table_name = 'user_roles'\n ) AS has_user_roles\n `);\n const hasLegacyTables = (legacyCheck.rows[0] as { has_user_roles: boolean }).has_user_roles;\n\n if (hasLegacyTables) {\n logger.info(\"🔄 Migrating roles from legacy user_roles table...\");\n // Update users' roles column from the junction table\n await db.execute(sql`\n UPDATE ${sql.raw(usersTableName)} u\n SET roles = COALESCE((\n SELECT array_agg(ur.role_id)\n FROM \"rebase\".\"user_roles\" ur\n WHERE ur.user_id = u.id\n ), '{}')\n WHERE u.roles = '{}' OR u.roles IS NULL\n `);\n\n // Drop legacy tables (junction first due to FK)\n await db.execute(sql`DROP TABLE IF EXISTS \"rebase\".\"user_roles\" CASCADE`);\n await db.execute(sql`DROP TABLE IF EXISTS \"rebase\".\"roles\" CASCADE`);\n logger.info(\"✅ Legacy roles tables migrated and dropped\");\n }\n } catch (migrationError: unknown) {\n // Non-fatal: log and continue — the column exists and will work\n logger.warn(`⚠️ Legacy roles migration skipped: ${migrationError instanceof Error ? migrationError.message : String(migrationError)}`);\n }\n\n // ── MFA tables ──────────────────────────────────────────────────────\n const mfaFactorsTableName = `\"${authSchema}\".\"mfa_factors\"`;\n const mfaChallengesTableName = `\"${authSchema}\".\"mfa_challenges\"`;\n const recoveryCodesTableName = `\"${authSchema}\".\"recovery_codes\"`;\n\n // Create mfa_factors table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(mfaFactorsTableName)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,\n factor_type TEXT NOT NULL DEFAULT 'totp',\n secret_encrypted TEXT NOT NULL,\n friendly_name TEXT,\n verified BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `);\n\n // Create indexes on mfa_factors\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_mfa_factors_user\n ON ${sql.raw(mfaFactorsTableName)}(user_id)\n `);\n\n // Create mfa_challenges table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(mfaChallengesTableName)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n factor_id TEXT NOT NULL REFERENCES ${sql.raw(mfaFactorsTableName)}(id) ON DELETE CASCADE,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n verified_at TIMESTAMP WITH TIME ZONE,\n ip_address TEXT,\n expires_at TIMESTAMP WITH TIME ZONE NOT NULL\n )\n `);\n\n // Create indexes on mfa_challenges\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_mfa_challenges_factor\n ON ${sql.raw(mfaChallengesTableName)}(factor_id)\n `);\n\n // Create recovery_codes table\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS ${sql.raw(recoveryCodesTableName)} (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n user_id ${sql.raw(userIdType)} NOT NULL REFERENCES ${sql.raw(usersTableName)}(id) ON DELETE CASCADE,\n code_hash TEXT NOT NULL,\n used_at TIMESTAMP WITH TIME ZONE,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `);\n\n // Create indexes on recovery_codes\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_recovery_codes_user\n ON ${sql.raw(recoveryCodesTableName)}(user_id)\n `);\n\n logger.info(\"✅ Auth tables ready\");\n } catch (error) {\n logger.error(\"❌ Failed to create auth tables\", { error });\n logger.warn(\"⚠️ Continuing without creating auth tables.\");\n }\n}\n\n","import { eq, getTableName, sql } from \"drizzle-orm\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { getTableConfig } from \"drizzle-orm/pg-core\";\nimport type { RebasePgTable } from \"../types\";\nimport { users, refreshTokens, passwordResetTokens, userIdentities } from \"../schema/auth-schema\";\nimport {\n UserRepository,\n RoleRepository,\n TokenRepository,\n MfaRepository,\n AuthRepository,\n UserData,\n CreateUserData,\n RoleData,\n CreateRoleData,\n RefreshTokenInfo,\n PasswordResetTokenInfo,\n UserIdentityData,\n ListUsersOptions,\n PaginatedUsersResult,\n MfaFactor,\n MfaChallengeInfo,\n RoleData as Role\n} from \"@rebasepro/server-core\";\nimport { toSnakeCase, camelCase } from \"@rebasepro/utils\";\n\nexport type { Role };\n\nexport interface AuthSchemaTables {\n users: RebasePgTable;\n refreshTokens: RebasePgTable;\n passwordResetTokens: RebasePgTable;\n appConfig: RebasePgTable;\n userIdentities: RebasePgTable;\n}\n\nfunction getColumnKey(table: RebasePgTable | undefined, ...keys: string[]): string | undefined {\n if (!table) return undefined;\n for (const key of keys) {\n if (key in table) return key;\n const snake = toSnakeCase(key);\n if (snake in table) return snake;\n const camel = camelCase(key);\n if (camel in table) return camel;\n }\n return undefined;\n}\n\nfunction getColumn(table: RebasePgTable | undefined, ...keys: string[]): RebasePgTable[string] | undefined {\n if (!table) return undefined;\n const key = getColumnKey(table, ...keys);\n return key ? table[key] : undefined;\n}\n\n/**\n * PostgreSQL implementation of UserRepository.\n * Handles all user-related database operations using Drizzle ORM.\n */\nexport class UserService implements UserRepository {\n private usersTable: RebasePgTable;\n private userIdentitiesTable: RebasePgTable;\n\n constructor(\n private db: NodePgDatabase,\n tableOrTables?: RebasePgTable | Partial<AuthSchemaTables>\n ) {\n if (tableOrTables && ((tableOrTables as Partial<AuthSchemaTables>).users)) {\n const tables = tableOrTables as Partial<AuthSchemaTables>;\n this.usersTable = (tables.users || users) as RebasePgTable;\n this.userIdentitiesTable = (tables.userIdentities || userIdentities) as RebasePgTable;\n } else {\n const table = tableOrTables as RebasePgTable | undefined;\n this.usersTable = table || (users as unknown as RebasePgTable);\n this.userIdentitiesTable = userIdentities as unknown as RebasePgTable;\n }\n }\n\n private getQualifiedUsersTableName(): string {\n const name = getTableName(this.usersTable);\n const schema = getTableConfig(this.usersTable).schema || \"public\";\n return `\"${schema}\".\"${name}\"`;\n }\n\n private mapRowToUser(row: Record<string, unknown>): UserData {\n if (!row) return row as UserData;\n\n const id = (row.id ?? row.uid) as string;\n const email = row.email as string;\n const passwordHash = (row.password_hash ?? row.passwordHash ?? null) as string | null | undefined;\n const displayName = (row.display_name ?? row.displayName ?? null) as string | null | undefined;\n const photoUrl = (row.photo_url ?? row.photoUrl ?? row.photoURL ?? null) as string | null | undefined;\n const emailVerified = (row.email_verified ?? row.emailVerified ?? false) as boolean;\n const emailVerificationToken = (row.email_verification_token ?? row.emailVerificationToken ?? null) as string | null | undefined;\n const emailVerificationSentAt = (row.email_verification_sent_at ?? row.emailVerificationSentAt ?? null) as string | number | Date | null;\n const isAnonymous = (row.is_anonymous ?? row.isAnonymous ?? false) as boolean;\n const createdAt = (row.created_at ?? row.createdAt) as string | number | Date | undefined;\n const updatedAt = (row.updated_at ?? row.updatedAt) as string | number | Date | undefined;\n\n const metadata: Record<string, any> = { ...((row.metadata as Record<string, any> | undefined) || {}) };\n\n const knownKeys = new Set([\n \"id\", \"uid\", \"email\",\n \"password_hash\", \"passwordHash\",\n \"display_name\", \"displayName\",\n \"photo_url\", \"photoUrl\", \"photoURL\",\n \"email_verified\", \"emailVerified\",\n \"email_verification_token\", \"emailVerificationToken\",\n \"email_verification_sent_at\", \"emailVerificationSentAt\",\n \"is_anonymous\", \"isAnonymous\",\n \"roles\",\n \"created_at\", \"createdAt\",\n \"updated_at\", \"updatedAt\",\n \"metadata\"\n ]);\n\n for (const [key, val] of Object.entries(row)) {\n if (!knownKeys.has(key)) {\n const camelKey = camelCase(key);\n metadata[camelKey] = val;\n }\n }\n\n return {\n id,\n email,\n passwordHash,\n displayName,\n photoUrl,\n emailVerified,\n emailVerificationToken,\n emailVerificationSentAt: emailVerificationSentAt ? new Date(emailVerificationSentAt) : null,\n isAnonymous,\n createdAt: createdAt ? new Date(createdAt) : new Date(),\n updatedAt: updatedAt ? new Date(updatedAt) : new Date(),\n metadata\n };\n }\n\n private mapPayload(data: Partial<CreateUserData>): Record<string, unknown> {\n if (!data) return {};\n\n const payload: Record<string, unknown> = {};\n\n const idKey = getColumnKey(this.usersTable, \"id\") || \"id\";\n const emailKey = getColumnKey(this.usersTable, \"email\") || \"email\";\n const passwordHashKey = getColumnKey(this.usersTable, \"passwordHash\", \"password_hash\") || \"passwordHash\";\n const displayNameKey = getColumnKey(this.usersTable, \"displayName\", \"display_name\") || \"displayName\";\n const photoUrlKey = getColumnKey(this.usersTable, \"photoUrl\", \"photo_url\") || \"photoUrl\";\n const emailVerifiedKey = getColumnKey(this.usersTable, \"emailVerified\", \"email_verified\") || \"emailVerified\";\n const emailVerificationTokenKey = getColumnKey(this.usersTable, \"emailVerificationToken\", \"email_verification_token\") || \"emailVerificationToken\";\n const emailVerificationSentAtKey = getColumnKey(this.usersTable, \"emailVerificationSentAt\", \"email_verification_sent_at\") || \"emailVerificationSentAt\";\n const isAnonymousKey = getColumnKey(this.usersTable, \"isAnonymous\", \"is_anonymous\") || \"isAnonymous\";\n const createdAtKey = getColumnKey(this.usersTable, \"createdAt\", \"created_at\") || \"createdAt\";\n const updatedAtKey = getColumnKey(this.usersTable, \"updatedAt\", \"updated_at\") || \"updatedAt\";\n const metadataKey = getColumnKey(this.usersTable, \"metadata\") || \"metadata\";\n\n if (\"id\" in data) payload[idKey] = data.id;\n if (\"email\" in data) payload[emailKey] = data.email;\n if (\"passwordHash\" in data) payload[passwordHashKey] = data.passwordHash;\n if (\"displayName\" in data) payload[displayNameKey] = data.displayName;\n if (\"photoUrl\" in data) payload[photoUrlKey] = data.photoUrl;\n if (\"emailVerified\" in data) payload[emailVerifiedKey] = data.emailVerified;\n if (\"emailVerificationToken\" in data) payload[emailVerificationTokenKey] = data.emailVerificationToken;\n if (\"emailVerificationSentAt\" in data) payload[emailVerificationSentAtKey] = data.emailVerificationSentAt;\n if (\"isAnonymous\" in data) payload[isAnonymousKey] = data.isAnonymous;\n if (\"createdAt\" in data) payload[createdAtKey] = data.createdAt;\n if (\"updatedAt\" in data) payload[updatedAtKey] = data.updatedAt;\n\n const metadata: Record<string, any> = { ...(data.metadata || {}) };\n const remainingMetadata: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(metadata)) {\n const tableColKey = getColumnKey(this.usersTable, key);\n if (tableColKey &&\n tableColKey !== idKey &&\n tableColKey !== emailKey &&\n tableColKey !== passwordHashKey &&\n tableColKey !== displayNameKey &&\n tableColKey !== photoUrlKey &&\n tableColKey !== emailVerifiedKey &&\n tableColKey !== emailVerificationTokenKey &&\n tableColKey !== emailVerificationSentAtKey &&\n tableColKey !== isAnonymousKey &&\n tableColKey !== createdAtKey &&\n tableColKey !== updatedAtKey &&\n tableColKey !== metadataKey) {\n payload[tableColKey] = val;\n } else {\n remainingMetadata[key] = val;\n }\n }\n\n if (metadataKey in this.usersTable) {\n payload[metadataKey] = remainingMetadata;\n }\n\n return payload;\n }\n\n async createUser(data: CreateUserData): Promise<UserData> {\n const payload = this.mapPayload(data);\n const [row] = (await this.db.insert(this.usersTable).values(payload).returning()) as Record<string, unknown>[];\n return this.mapRowToUser(row);\n }\n\n async getUserById(id: string): Promise<UserData | null> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return null;\n const [row] = await this.db.select().from(this.usersTable).where(eq(idCol, id));\n return row ? this.mapRowToUser(row as Record<string, unknown>) : null;\n }\n\n async getUserByEmail(email: string): Promise<UserData | null> {\n const emailCol = getColumn(this.usersTable, \"email\");\n if (!emailCol) return null;\n const [row] = await this.db.select().from(this.usersTable).where(eq(emailCol, email.toLowerCase()));\n return row ? this.mapRowToUser(row as Record<string, unknown>) : null;\n }\n\n async getUserByIdentity(provider: string, providerId: string): Promise<UserData | null> {\n const userIdCol = getColumn(this.usersTable, \"id\");\n if (!userIdCol) return null;\n\n const result = await this.db\n .select({ user: this.usersTable })\n .from(this.usersTable)\n .innerJoin(this.userIdentitiesTable, eq(userIdCol, this.userIdentitiesTable.userId))\n .where(\n sql`${this.userIdentitiesTable.provider} = ${provider} AND ${this.userIdentitiesTable.providerId} = ${providerId}`\n )\n .limit(1);\n\n if (result.length === 0) return null;\n return this.mapRowToUser(result[0].user as Record<string, unknown>);\n }\n\n async getUserIdentities(userId: string): Promise<UserIdentityData[]> {\n const schema = getTableConfig(this.userIdentitiesTable).schema || \"public\";\n const result = await this.db.execute(sql`\n SELECT id, user_id, provider, provider_id, profile_data, created_at, updated_at\n FROM ${sql.raw(`\"${schema}\".\"user_identities\"`)}\n WHERE user_id = ${userId}\n `);\n\n return result.rows.map((row: Record<string, unknown>) => ({\n id: row.id as string,\n userId: row.user_id as string,\n provider: row.provider as string,\n providerId: row.provider_id as string,\n profileData: (row.profile_data as Record<string, unknown> | null) ?? null,\n createdAt: row.created_at as Date,\n updatedAt: row.updated_at as Date\n }));\n }\n\n async linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n await this.db.insert(this.userIdentitiesTable).values({\n userId,\n provider,\n providerId,\n profileData: profileData || null\n }).onConflictDoNothing({ target: [this.userIdentitiesTable.provider, this.userIdentitiesTable.providerId] });\n }\n\n async updateUser(id: string, data: Partial<Omit<CreateUserData, \"id\">>): Promise<UserData | null> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return null;\n const payload = this.mapPayload(data);\n const updatedAtKey = getColumnKey(this.usersTable, \"updatedAt\", \"updated_at\") || \"updatedAt\";\n payload[updatedAtKey] = new Date();\n\n const [row] = (await this.db\n .update(this.usersTable)\n .set(payload)\n .where(eq(idCol, id))\n .returning()) as Record<string, unknown>[];\n return row ? this.mapRowToUser(row) : null;\n }\n\n async deleteUser(id: string): Promise<void> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return;\n await this.db.delete(this.usersTable).where(eq(idCol, id));\n }\n\n async listUsers(): Promise<UserData[]> {\n const rows = await this.db.select().from(this.usersTable);\n return (rows as Record<string, unknown>[]).map(row => this.mapRowToUser(row));\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 orderCol = getColumn(this.usersTable, orderBy);\n const orderColumn = orderCol ? orderCol.name : \"created_at\";\n const direction = orderDir === \"asc\" ? sql`ASC` : sql`DESC`;\n\n const emailCol = getColumn(this.usersTable, \"email\");\n const emailColumn = emailCol ? emailCol.name : \"email\";\n const displayNameCol = getColumn(this.usersTable, \"displayName\", \"display_name\");\n const displayNameColumn = displayNameCol ? displayNameCol.name : \"display_name\";\n const idCol = getColumn(this.usersTable, \"id\");\n const idColumn = idCol ? idCol.name : \"id\";\n\n const usersTableName = this.getQualifiedUsersTableName();\n const conditions = [];\n if (roleId) {\n conditions.push(sql`${roleId} = ANY(${sql.raw(usersTableName)}.roles)`);\n }\n if (search) {\n const pattern = `%${search}%`;\n conditions.push(sql`(${sql.raw(usersTableName)}.${sql.raw(emailColumn)} ILIKE ${pattern} OR ${sql.raw(usersTableName)}.${sql.raw(displayNameColumn)} ILIKE ${pattern})`);\n }\n\n const whereClause = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;\n\n // Sorting: users with roles first if no role filter, then by requested order\n const orderByClause = roleId\n ? sql`ORDER BY ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}`\n : sql`ORDER BY array_length(${sql.raw(usersTableName)}.roles, 1) DESC NULLS LAST, ${sql.raw(usersTableName)}.${sql.raw(orderColumn)} ${direction}`;\n\n const countResult = await this.db.execute(sql`\n SELECT count(*)::int as total FROM ${sql.raw(usersTableName)}\n ${whereClause}\n `);\n const total = (countResult.rows[0] as { total: number }).total;\n\n const dataResult = await this.db.execute(sql`\n SELECT * FROM ${sql.raw(usersTableName)}\n ${whereClause}\n ${orderByClause}\n LIMIT ${limit} OFFSET ${offset}\n `);\n const rows = dataResult.rows;\n\n // Map rows to camelCase UserData\n const mappedUsers: UserData[] = (rows as Record<string, unknown>[]).map((row) => this.mapRowToUser(row));\n\n return { users: mappedUsers,\n total,\n limit,\n offset };\n }\n\n /**\n * Update user's password hash\n */\n async updatePassword(id: string, passwordHash: string): Promise<void> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return;\n const passwordHashColKey = getColumnKey(this.usersTable, \"passwordHash\", \"password_hash\") || \"passwordHash\";\n const updatedAtColKey = getColumnKey(this.usersTable, \"updatedAt\", \"updated_at\") || \"updatedAt\";\n\n await this.db\n .update(this.usersTable)\n .set({\n [passwordHashColKey]: passwordHash,\n [updatedAtColKey]: new Date()\n })\n .where(eq(idCol, id));\n }\n\n /**\n * Set email verification status\n */\n async setEmailVerified(id: string, verified: boolean): Promise<void> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return;\n const emailVerifiedColKey = getColumnKey(this.usersTable, \"emailVerified\", \"email_verified\") || \"emailVerified\";\n const emailVerificationTokenColKey = getColumnKey(this.usersTable, \"emailVerificationToken\", \"email_verification_token\") || \"emailVerificationToken\";\n const updatedAtColKey = getColumnKey(this.usersTable, \"updatedAt\", \"updated_at\") || \"updatedAt\";\n\n await this.db\n .update(this.usersTable)\n .set({\n [emailVerifiedColKey]: verified,\n [emailVerificationTokenColKey]: null,\n [updatedAtColKey]: new Date()\n })\n .where(eq(idCol, id));\n }\n\n /**\n * Set email verification token\n */\n async setVerificationToken(id: string, token: string | null): Promise<void> {\n const idCol = getColumn(this.usersTable, \"id\");\n if (!idCol) return;\n const emailVerificationTokenColKey = getColumnKey(this.usersTable, \"emailVerificationToken\", \"email_verification_token\") || \"emailVerificationToken\";\n const emailVerificationSentAtColKey = getColumnKey(this.usersTable, \"emailVerificationSentAt\", \"email_verification_sent_at\") || \"emailVerificationSentAt\";\n const updatedAtColKey = getColumnKey(this.usersTable, \"updatedAt\", \"updated_at\") || \"updatedAt\";\n\n await this.db\n .update(this.usersTable)\n .set({\n [emailVerificationTokenColKey]: token,\n [emailVerificationSentAtColKey]: token ? new Date() : null,\n [updatedAtColKey]: new Date()\n })\n .where(eq(idCol, id));\n }\n\n /**\n * Find user by email verification token\n */\n async getUserByVerificationToken(token: string): Promise<UserData | null> {\n const tokenCol = getColumn(this.usersTable, \"emailVerificationToken\", \"email_verification_token\");\n if (!tokenCol) return null;\n const [row] = await this.db\n .select()\n .from(this.usersTable)\n .where(eq(tokenCol, token));\n return row ? this.mapRowToUser(row as Record<string, unknown>) : null;\n }\n\n /**\n * Get roles for a user from database (inline TEXT[] column)\n */\n async getUserRoles(userId: string): Promise<Role[]> {\n const usersTableName = this.getQualifiedUsersTableName();\n const result = await this.db.execute(sql`\n SELECT roles FROM ${sql.raw(usersTableName)} WHERE id = ${userId}\n `);\n\n if (result.rows.length === 0) return [];\n\n const row = result.rows[0] as { roles: string[] | null };\n const roleIds = row.roles ?? [];\n\n return roleIds.map(id => ({\n id,\n name: id,\n isAdmin: id === \"admin\",\n defaultPermissions: null,\n collectionPermissions: null\n }));\n }\n\n /**\n * Get role IDs for a user\n */\n async getUserRoleIds(userId: string): Promise<string[]> {\n const usersTableName = this.getQualifiedUsersTableName();\n const result = await this.db.execute(sql`\n SELECT roles FROM ${sql.raw(usersTableName)} WHERE id = ${userId}\n `);\n\n if (result.rows.length === 0) return [];\n\n const row = result.rows[0] as { roles: string[] | null };\n return row.roles ?? [];\n }\n\n /**\n * Set roles for a user (replaces existing roles)\n */\n async setUserRoles(userId: string, roleIds: string[]): Promise<void> {\n const usersTableName = this.getQualifiedUsersTableName();\n const rolesArray = `{${roleIds.join(\",\")}}`;\n await this.db.execute(sql`\n UPDATE ${sql.raw(usersTableName)}\n SET roles = ${rolesArray}::text[], updated_at = NOW()\n WHERE id = ${userId}\n `);\n }\n\n /**\n * Assign a specific role to new user (appends if not present)\n */\n async assignDefaultRole(userId: string, roleId: string): Promise<void> {\n const usersTableName = this.getQualifiedUsersTableName();\n await this.db.execute(sql`\n UPDATE ${sql.raw(usersTableName)}\n SET roles = array_append(roles, ${roleId}), updated_at = NOW()\n WHERE id = ${userId} AND NOT (${roleId} = ANY(roles))\n `);\n }\n\n /**\n * Get user with their roles\n */\n async getUserWithRoles(userId: string): Promise<{ user: UserData; roles: Role[] } | null> {\n const user = await this.getUserById(userId);\n if (!user) return null;\n\n const roles = await this.getUserRoles(userId);\n return { user,\n roles };\n }\n}\n\n\nexport class RefreshTokenService {\n private refreshTokensTable: RebasePgTable;\n\n constructor(\n private db: NodePgDatabase,\n tableOrTables?: RebasePgTable | Partial<AuthSchemaTables>\n ) {\n if (tableOrTables && ((tableOrTables as Partial<AuthSchemaTables>).refreshTokens || (tableOrTables as Partial<AuthSchemaTables>).users)) {\n this.refreshTokensTable = ((tableOrTables as Partial<AuthSchemaTables>).refreshTokens || refreshTokens) as RebasePgTable;\n } else {\n this.refreshTokensTable = (tableOrTables as RebasePgTable) || (refreshTokens as unknown as RebasePgTable);\n }\n }\n\n private getQualifiedRefreshTokensTableName(): string {\n const name = getTableName(this.refreshTokensTable);\n const schema = getTableConfig(this.refreshTokensTable).schema || \"public\";\n return `\"${schema}\".\"${name}\"`;\n }\n\n async createToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void> {\n // Fallback to empty string because UNIQUE constraints treat NULLs as strictly distinct in standard Postgres.\n // We want (userId, NULL, NULL) to collide and overwrite, so we map undefined/null to empty strings.\n const safeUserAgent = userAgent || \"\";\n const safeIpAddress = ipAddress || \"\";\n\n // Delete any existing session for this user/device combo, then insert.\n // This approach doesn't require the unique_device_session constraint to exist.\n const tableName = this.getQualifiedRefreshTokensTableName();\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)} \n WHERE user_id = ${userId} \n AND user_agent = ${safeUserAgent} \n AND ip_address = ${safeIpAddress}\n `);\n\n await this.db.insert(this.refreshTokensTable)\n .values({\n userId,\n tokenHash,\n expiresAt,\n userAgent: safeUserAgent,\n ipAddress: safeIpAddress\n });\n }\n\n async findByHash(tokenHash: string): Promise<RefreshTokenInfo | null> {\n const [token] = await this.db\n .select({\n id: this.refreshTokensTable.id,\n userId: this.refreshTokensTable.userId,\n tokenHash: this.refreshTokensTable.tokenHash,\n expiresAt: this.refreshTokensTable.expiresAt,\n createdAt: this.refreshTokensTable.createdAt,\n userAgent: this.refreshTokensTable.userAgent,\n ipAddress: this.refreshTokensTable.ipAddress\n })\n .from(this.refreshTokensTable)\n .where(eq(this.refreshTokensTable.tokenHash, tokenHash));\n\n return (token as RefreshTokenInfo) || null;\n }\n\n async deleteByHash(tokenHash: string): Promise<void> {\n await this.db.delete(this.refreshTokensTable).where(eq(this.refreshTokensTable.tokenHash, tokenHash));\n }\n\n async deleteAllForUser(userId: string): Promise<void> {\n await this.db.delete(this.refreshTokensTable).where(eq(this.refreshTokensTable.userId, userId));\n }\n\n async listForUser(userId: string): Promise<RefreshTokenInfo[]> {\n const tokens = await this.db\n .select({\n id: this.refreshTokensTable.id,\n userId: this.refreshTokensTable.userId,\n tokenHash: this.refreshTokensTable.tokenHash,\n expiresAt: this.refreshTokensTable.expiresAt,\n createdAt: this.refreshTokensTable.createdAt,\n userAgent: this.refreshTokensTable.userAgent,\n ipAddress: this.refreshTokensTable.ipAddress\n })\n .from(this.refreshTokensTable)\n .where(eq(this.refreshTokensTable.userId, userId))\n .orderBy(this.refreshTokensTable.createdAt);\n\n return tokens as RefreshTokenInfo[];\n }\n\n async deleteById(id: string, userId: string): Promise<void> {\n await this.db.delete(this.refreshTokensTable)\n .where(sql`${this.refreshTokensTable.id} = ${id} AND ${this.refreshTokensTable.userId} = ${userId}`);\n }\n}\n\n/**\n * Password reset token service\n */\nexport class PasswordResetTokenService {\n private passwordResetTokensTable: RebasePgTable;\n\n constructor(\n private db: NodePgDatabase,\n tableOrTables?: RebasePgTable | Partial<AuthSchemaTables>\n ) {\n if (tableOrTables && ((tableOrTables as Partial<AuthSchemaTables>).passwordResetTokens || (tableOrTables as Partial<AuthSchemaTables>).users)) {\n this.passwordResetTokensTable = ((tableOrTables as Partial<AuthSchemaTables>).passwordResetTokens || passwordResetTokens) as RebasePgTable;\n } else {\n this.passwordResetTokensTable = (tableOrTables as RebasePgTable) || (passwordResetTokens as unknown as RebasePgTable);\n }\n }\n\n private getQualifiedPasswordResetTokensTableName(): string {\n const name = getTableName(this.passwordResetTokensTable);\n const schema = getTableConfig(this.passwordResetTokensTable).schema || \"public\";\n return `\"${schema}\".\"${name}\"`;\n }\n\n /**\n * Create a password reset token\n */\n async createToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void> {\n // Delete any existing unused tokens for this user\n const tableName = this.getQualifiedPasswordResetTokensTableName();\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)} \n WHERE user_id = ${userId} AND used_at IS NULL\n `);\n\n await this.db.insert(this.passwordResetTokensTable).values({\n userId,\n tokenHash,\n expiresAt\n });\n }\n\n /**\n * Find a valid (not expired, not used) token by hash\n */\n async findValidByHash(tokenHash: string): Promise<{ userId: string; expiresAt: Date } | null> {\n const [token] = await this.db\n .select({\n userId: this.passwordResetTokensTable.userId,\n expiresAt: this.passwordResetTokensTable.expiresAt\n })\n .from(this.passwordResetTokensTable)\n .where(eq(this.passwordResetTokensTable.tokenHash, tokenHash)) as unknown as Array<{ userId: string; expiresAt: Date }>;\n\n if (!token) return null;\n\n // Check if expired or used\n const tableName = this.getQualifiedPasswordResetTokensTableName();\n const result = await this.db.execute(sql`\n SELECT user_id, expires_at \n FROM ${sql.raw(tableName)} \n WHERE token_hash = ${tokenHash} \n AND used_at IS NULL \n AND expires_at > NOW()\n `);\n\n if (result.rows.length === 0) return null;\n\n const row = result.rows[0] as { user_id: string; expires_at: string | number | Date };\n return {\n userId: row.user_id,\n expiresAt: new Date(row.expires_at)\n };\n }\n\n /**\n * Mark token as used\n */\n async markAsUsed(tokenHash: string): Promise<void> {\n await this.db\n .update(this.passwordResetTokensTable)\n .set({ usedAt: new Date() })\n .where(eq(this.passwordResetTokensTable.tokenHash, tokenHash));\n }\n\n /**\n * Delete all tokens for a user\n */\n async deleteAllForUser(userId: string): Promise<void> {\n await this.db.delete(this.passwordResetTokensTable).where(eq(this.passwordResetTokensTable.userId, userId));\n }\n\n /**\n * Clean up expired tokens\n */\n async deleteExpired(): Promise<void> {\n const tableName = this.getQualifiedPasswordResetTokensTableName();\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)} \n WHERE expires_at < NOW()\n `);\n }\n}\n\n/**\n * PostgreSQL implementation of TokenRepository.\n * Combines refresh token and password reset token operations.\n */\nexport class PostgresTokenRepository implements TokenRepository {\n private refreshTokenService: RefreshTokenService;\n private passwordResetTokenService: PasswordResetTokenService;\n\n constructor(\n private db: NodePgDatabase,\n tableOrTables?: RebasePgTable | Partial<AuthSchemaTables>\n ) {\n this.refreshTokenService = new RefreshTokenService(db, tableOrTables);\n this.passwordResetTokenService = new PasswordResetTokenService(db, tableOrTables);\n }\n\n // Refresh token operations\n\n async createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void> {\n await this.refreshTokenService.createToken(userId, tokenHash, expiresAt, userAgent, ipAddress);\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(userId: string): Promise<void> {\n await this.refreshTokenService.deleteAllForUser(userId);\n }\n\n async listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]> {\n return this.refreshTokenService.listForUser(userId);\n }\n\n async deleteRefreshTokenById(id: string, userId: string): Promise<void> {\n await this.refreshTokenService.deleteById(id, userId);\n }\n\n // Password reset token operations\n\n async createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.passwordResetTokenService.createToken(userId, 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(userId: string): Promise<void> {\n await this.passwordResetTokenService.deleteAllForUser(userId);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.passwordResetTokenService.deleteExpired();\n }\n}\n\n/**\n * PostgreSQL implementation of AuthRepository.\n * Combines user, role, and token repository operations.\n * This provides a convenient single-class interface for all auth operations.\n */\nexport class PostgresAuthRepository implements AuthRepository {\n private userService: UserService;\n private tokenRepository: PostgresTokenRepository;\n\n constructor(\n private db: NodePgDatabase,\n tableOrTables?: RebasePgTable | Partial<AuthSchemaTables>\n ) {\n this.userService = new UserService(db, tableOrTables);\n this.tokenRepository = new PostgresTokenRepository(db, tableOrTables);\n }\n\n // User operations (delegate to UserService)\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(userId: string): Promise<UserIdentityData[]> {\n return this.userService.getUserIdentities(userId);\n }\n\n async linkUserIdentity(userId: string, provider: string, providerId: string, profileData?: Record<string, unknown>): Promise<void> {\n return this.userService.linkUserIdentity(userId, 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(userId: string): Promise<RoleData[]> {\n return this.userService.getUserRoles(userId);\n }\n\n async getUserRoleIds(userId: string): Promise<string[]> {\n return this.userService.getUserRoleIds(userId);\n }\n\n async setUserRoles(userId: string, roleIds: string[]): Promise<void> {\n await this.userService.setUserRoles(userId, roleIds);\n }\n\n async assignDefaultRole(userId: string, roleId: string): Promise<void> {\n await this.userService.assignDefaultRole(userId, roleId);\n }\n\n async getUserWithRoles(userId: string): Promise<{ user: UserData; roles: RoleData[] } | null> {\n return this.userService.getUserWithRoles(userId);\n }\n\n // Role operations (roles are inline on users, synthesized from string IDs)\n\n async getRoleById(id: string): Promise<RoleData | null> {\n return {\n id,\n name: id,\n isAdmin: id === \"admin\",\n defaultPermissions: null,\n collectionPermissions: null\n };\n }\n\n async listRoles(): Promise<RoleData[]> {\n return [\n { id: \"admin\",\nname: \"Admin\",\nisAdmin: true,\ndefaultPermissions: null,\ncollectionPermissions: null },\n { id: \"editor\",\nname: \"Editor\",\nisAdmin: false,\ndefaultPermissions: null,\ncollectionPermissions: null },\n { id: \"viewer\",\nname: \"Viewer\",\nisAdmin: false,\ndefaultPermissions: null,\ncollectionPermissions: null }\n ];\n }\n\n async createRole(_data: CreateRoleData): Promise<RoleData> {\n return {\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 }\n\n async updateRole(id: string, data: Partial<Omit<RoleData, \"id\">>): Promise<RoleData | null> {\n return {\n id,\n name: data.name ?? id,\n isAdmin: data.isAdmin ?? (id === \"admin\"),\n defaultPermissions: data.defaultPermissions ?? null,\n collectionPermissions: data.collectionPermissions ?? null\n };\n }\n\n async deleteRole(_id: string): Promise<void> {\n // No-op: roles are inline strings on users\n }\n\n // Token operations (delegate to PostgresTokenRepository)\n\n async createRefreshToken(userId: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void> {\n await this.tokenRepository.createRefreshToken(userId, tokenHash, expiresAt, userAgent, ipAddress);\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(userId: string): Promise<void> {\n await this.tokenRepository.deleteAllRefreshTokensForUser(userId);\n }\n\n async listRefreshTokensForUser(userId: string): Promise<RefreshTokenInfo[]> {\n return this.tokenRepository.listRefreshTokensForUser(userId);\n }\n\n async deleteRefreshTokenById(id: string, userId: string): Promise<void> {\n await this.tokenRepository.deleteRefreshTokenById(id, userId);\n }\n\n async createPasswordResetToken(userId: string, tokenHash: string, expiresAt: Date): Promise<void> {\n await this.tokenRepository.createPasswordResetToken(userId, 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(userId: string): Promise<void> {\n await this.tokenRepository.deleteAllPasswordResetTokensForUser(userId);\n }\n\n async deleteExpiredTokens(): Promise<void> {\n await this.tokenRepository.deleteExpiredTokens();\n }\n\n // MFA operations (delegate to MfaService)\n\n private _mfaService: MfaService | null = null;\n private getMfaService(): MfaService {\n if (!this._mfaService) {\n this._mfaService = new MfaService(this.db);\n }\n return this._mfaService;\n }\n\n async createMfaFactor(userId: string, factorType: \"totp\", secretEncrypted: string, friendlyName?: string): Promise<MfaFactor> {\n return this.getMfaService().createMfaFactor(userId, factorType, secretEncrypted, friendlyName);\n }\n\n async getMfaFactors(userId: string): Promise<MfaFactor[]> {\n return this.getMfaService().getMfaFactors(userId);\n }\n\n async getMfaFactorById(factorId: string): Promise<(MfaFactor & { secretEncrypted: string }) | null> {\n return this.getMfaService().getMfaFactorById(factorId);\n }\n\n async verifyMfaFactor(factorId: string): Promise<void> {\n return this.getMfaService().verifyMfaFactor(factorId);\n }\n\n async deleteMfaFactor(factorId: string, userId: string): Promise<void> {\n return this.getMfaService().deleteMfaFactor(factorId, userId);\n }\n\n async createMfaChallenge(factorId: string, ipAddress?: string): Promise<MfaChallengeInfo> {\n return this.getMfaService().createMfaChallenge(factorId, ipAddress);\n }\n\n async getMfaChallengeById(challengeId: string): Promise<MfaChallengeInfo | null> {\n return this.getMfaService().getMfaChallengeById(challengeId);\n }\n\n async verifyMfaChallenge(challengeId: string): Promise<void> {\n return this.getMfaService().verifyMfaChallenge(challengeId);\n }\n\n async createRecoveryCodes(userId: string, codeHashes: string[]): Promise<void> {\n return this.getMfaService().createRecoveryCodes(userId, codeHashes);\n }\n\n async useRecoveryCode(userId: string, codeHash: string): Promise<boolean> {\n return this.getMfaService().useRecoveryCode(userId, codeHash);\n }\n\n async getUnusedRecoveryCodeCount(userId: string): Promise<number> {\n return this.getMfaService().getUnusedRecoveryCodeCount(userId);\n }\n\n async deleteAllRecoveryCodes(userId: string): Promise<void> {\n return this.getMfaService().deleteAllRecoveryCodes(userId);\n }\n\n async hasVerifiedMfaFactors(userId: string): Promise<boolean> {\n return this.getMfaService().hasVerifiedMfaFactors(userId);\n }\n}\n\n// =============================================================================\n// MFA SERVICE\n// =============================================================================\n\n/**\n * PostgreSQL implementation of MfaRepository.\n * Handles all MFA-related database operations.\n */\nexport class MfaService implements MfaRepository {\n constructor(private db: NodePgDatabase, private schemaName = \"rebase\") {}\n\n private qualify(tableName: string): string {\n return `\"${this.schemaName}\".\"${tableName}\"`;\n }\n\n async createMfaFactor(\n userId: string,\n factorType: \"totp\",\n secretEncrypted: string,\n friendlyName?: string\n ): Promise<MfaFactor> {\n const tableName = this.qualify(\"mfa_factors\");\n const result = await this.db.execute(sql`\n INSERT INTO ${sql.raw(tableName)} (user_id, factor_type, secret_encrypted, friendly_name)\n VALUES (${userId}, ${factorType}, ${secretEncrypted}, ${friendlyName ?? null})\n RETURNING id, user_id, factor_type, friendly_name, verified, created_at, updated_at\n `);\n\n const row = result.rows[0] as Record<string, unknown>;\n return {\n id: row.id as string,\n userId: row.user_id as string,\n factorType: row.factor_type as \"totp\",\n friendlyName: (row.friendly_name as string | null) ?? undefined,\n verified: row.verified as boolean,\n createdAt: new Date(row.created_at as string),\n updatedAt: new Date(row.updated_at as string)\n };\n }\n\n async getMfaFactors(userId: string): Promise<MfaFactor[]> {\n const tableName = this.qualify(\"mfa_factors\");\n const result = await this.db.execute(sql`\n SELECT id, user_id, factor_type, friendly_name, verified, created_at, updated_at\n FROM ${sql.raw(tableName)}\n WHERE user_id = ${userId}\n ORDER BY created_at\n `);\n\n return (result.rows as Array<Record<string, unknown>>).map(row => ({\n id: row.id as string,\n userId: row.user_id as string,\n factorType: row.factor_type as \"totp\",\n friendlyName: (row.friendly_name as string | null) ?? undefined,\n verified: row.verified as boolean,\n createdAt: new Date(row.created_at as string),\n updatedAt: new Date(row.updated_at as string)\n }));\n }\n\n async getMfaFactorById(factorId: string): Promise<(MfaFactor & { secretEncrypted: string }) | null> {\n const tableName = this.qualify(\"mfa_factors\");\n const result = await this.db.execute(sql`\n SELECT id, user_id, factor_type, secret_encrypted, friendly_name, verified, created_at, updated_at\n FROM ${sql.raw(tableName)}\n WHERE id = ${factorId}\n `);\n\n if (result.rows.length === 0) return null;\n\n const row = result.rows[0] as Record<string, unknown>;\n return {\n id: row.id as string,\n userId: row.user_id as string,\n factorType: row.factor_type as \"totp\",\n secretEncrypted: row.secret_encrypted as string,\n friendlyName: (row.friendly_name as string | null) ?? undefined,\n verified: row.verified as boolean,\n createdAt: new Date(row.created_at as string),\n updatedAt: new Date(row.updated_at as string)\n };\n }\n\n async verifyMfaFactor(factorId: string): Promise<void> {\n const tableName = this.qualify(\"mfa_factors\");\n await this.db.execute(sql`\n UPDATE ${sql.raw(tableName)}\n SET verified = TRUE, updated_at = NOW()\n WHERE id = ${factorId}\n `);\n }\n\n async deleteMfaFactor(factorId: string, userId: string): Promise<void> {\n const tableName = this.qualify(\"mfa_factors\");\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)}\n WHERE id = ${factorId} AND user_id = ${userId}\n `);\n }\n\n async createMfaChallenge(factorId: string, ipAddress?: string): Promise<MfaChallengeInfo> {\n const tableName = this.qualify(\"mfa_challenges\");\n // Challenges expire in 5 minutes\n const expiresAt = new Date(Date.now() + 5 * 60 * 1000);\n const result = await this.db.execute(sql`\n INSERT INTO ${sql.raw(tableName)} (factor_id, ip_address, expires_at)\n VALUES (${factorId}, ${ipAddress ?? null}, ${expiresAt})\n RETURNING id, factor_id, created_at, verified_at, ip_address\n `);\n\n const row = result.rows[0] as Record<string, unknown>;\n return {\n id: row.id as string,\n factorId: row.factor_id as string,\n createdAt: new Date(row.created_at as string),\n verifiedAt: row.verified_at ? new Date(row.verified_at as string) : undefined,\n ipAddress: (row.ip_address as string | null) ?? undefined\n };\n }\n\n async getMfaChallengeById(challengeId: string): Promise<MfaChallengeInfo | null> {\n const tableName = this.qualify(\"mfa_challenges\");\n const result = await this.db.execute(sql`\n SELECT id, factor_id, created_at, verified_at, ip_address, expires_at\n FROM ${sql.raw(tableName)}\n WHERE id = ${challengeId} AND expires_at > NOW() AND verified_at IS NULL\n `);\n\n if (result.rows.length === 0) return null;\n\n const row = result.rows[0] as Record<string, unknown>;\n return {\n id: row.id as string,\n factorId: row.factor_id as string,\n createdAt: new Date(row.created_at as string),\n verifiedAt: row.verified_at ? new Date(row.verified_at as string) : undefined,\n ipAddress: (row.ip_address as string | null) ?? undefined\n };\n }\n\n async verifyMfaChallenge(challengeId: string): Promise<void> {\n const tableName = this.qualify(\"mfa_challenges\");\n await this.db.execute(sql`\n UPDATE ${sql.raw(tableName)}\n SET verified_at = NOW()\n WHERE id = ${challengeId}\n `);\n }\n\n async createRecoveryCodes(userId: string, codeHashes: string[]): Promise<void> {\n const tableName = this.qualify(\"recovery_codes\");\n // Delete existing codes first\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)} WHERE user_id = ${userId}\n `);\n\n // Insert new codes\n for (const hash of codeHashes) {\n await this.db.execute(sql`\n INSERT INTO ${sql.raw(tableName)} (user_id, code_hash)\n VALUES (${userId}, ${hash})\n `);\n }\n }\n\n async useRecoveryCode(userId: string, codeHash: string): Promise<boolean> {\n const tableName = this.qualify(\"recovery_codes\");\n const result = await this.db.execute(sql`\n UPDATE ${sql.raw(tableName)}\n SET used_at = NOW()\n WHERE user_id = ${userId} AND code_hash = ${codeHash} AND used_at IS NULL\n RETURNING id\n `);\n\n return result.rows.length > 0;\n }\n\n async getUnusedRecoveryCodeCount(userId: string): Promise<number> {\n const tableName = this.qualify(\"recovery_codes\");\n const result = await this.db.execute(sql`\n SELECT COUNT(*)::int as count FROM ${sql.raw(tableName)}\n WHERE user_id = ${userId} AND used_at IS NULL\n `);\n\n return (result.rows[0] as { count: number }).count;\n }\n\n async deleteAllRecoveryCodes(userId: string): Promise<void> {\n const tableName = this.qualify(\"recovery_codes\");\n await this.db.execute(sql`\n DELETE FROM ${sql.raw(tableName)} WHERE user_id = ${userId}\n `);\n }\n\n async hasVerifiedMfaFactors(userId: string): Promise<boolean> {\n const tableName = this.qualify(\"mfa_factors\");\n const result = await this.db.execute(sql`\n SELECT COUNT(*)::int as count FROM ${sql.raw(tableName)}\n WHERE user_id = ${userId} AND verified = TRUE\n `);\n\n return (result.rows[0] as { count: number }).count > 0;\n }\n}\n\n// =============================================================================\n// PostgreSQL Type Aliases (for consistent naming with other implementations)\n// =============================================================================\n\n/** PostgreSQL user repository implementation */\nexport type PostgresUserRepository = UserService;\n","import { sql } from \"drizzle-orm\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { logger } from \"@rebasepro/server-core\";\n\nexport interface HistoryEntry {\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: string;\n}\n\nexport interface RecordHistoryParams {\n tableName: string;\n entityId: 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 FetchHistoryOptions {\n limit?: number;\n offset?: number;\n}\n\nexport interface HistoryRetentionConfig {\n /** Max entries per entity. Oldest pruned first. Default 200. */\n maxEntries: number;\n /** Entries older than this many days are pruned. Default 90. */\n ttlDays: number;\n}\n\nconst DEFAULT_RETENTION: HistoryRetentionConfig = {\n maxEntries: 200,\n ttlDays: 90\n};\n\n/**\n * Service for recording and querying entity change history.\n * Stores snapshots in the `rebase.entity_history` table.\n */\nexport class HistoryService {\n public retention: HistoryRetentionConfig;\n\n constructor(\n private db: NodePgDatabase,\n retention?: Partial<HistoryRetentionConfig>\n ) {\n this.retention = { ...DEFAULT_RETENTION,\n...retention };\n }\n\n /**\n * Record a history entry for an entity change.\n * This is intentionally fire-and-forget safe — errors are logged but never\n * bubble up to block the main save/delete operation.\n *\n * After inserting, kicks off a non-blocking pruning pass for this entity.\n */\n async recordHistory(params: RecordHistoryParams): Promise<void> {\n const {\n tableName,\n entityId,\n action,\n values,\n previousValues,\n updatedBy\n } = params;\n\n const changedFields = previousValues && values\n ? findChangedFields(previousValues, values)\n : null;\n\n\n // Skip recording if this is an update with zero actual changes\n\n if (action === \"update\" && (!changedFields || changedFields.length === 0)) {\n return;\n }\n\n try {\n await this.db.execute(sql`\n INSERT INTO rebase.entity_history \n (table_name, entity_id, action, changed_fields, \"values\", previous_values, updated_by)\n VALUES (\n ${tableName},\n ${String(entityId)},\n ${action},\n ${changedFields ? sql`ARRAY[${sql.join(changedFields.map(f => sql`${f}`), sql`, `)}]::text[]` : sql`NULL`},\n ${values ? sql`${JSON.stringify(values)}::jsonb` : sql`NULL`},\n ${previousValues ? sql`${JSON.stringify(previousValues)}::jsonb` : sql`NULL`},\n ${updatedBy ?? null}\n )\n `);\n\n // Non-blocking prune for this specific entity\n this.pruneEntity(tableName, entityId).catch(err =>\n logger.error(\"History prune failed\", { error: err })\n );\n } catch (error) {\n logger.error(\"Failed to record entity history\", { error: error });\n }\n }\n\n /**\n * Fetch history entries for an entity, ordered by most recent first.\n */\n async fetchHistory(\n tableName: string,\n entityId: string,\n options: FetchHistoryOptions = {}\n ): Promise<{ data: HistoryEntry[]; total: number }> {\n const limit = options.limit ?? 20;\n const offset = options.offset ?? 0;\n\n const [countResult, dataResult] = await Promise.all([\n this.db.execute(sql`\n SELECT COUNT(*) as count\n FROM rebase.entity_history\n WHERE table_name = ${tableName}\n AND entity_id = ${String(entityId)}\n `),\n this.db.execute(sql`\n SELECT id, table_name, entity_id, action, changed_fields,\n \"values\", previous_values, updated_by, updated_at\n FROM rebase.entity_history\n WHERE table_name = ${tableName}\n AND entity_id = ${String(entityId)}\n ORDER BY updated_at DESC\n LIMIT ${limit}\n OFFSET ${offset}\n `)\n ]);\n\n const total = parseInt(\n (countResult.rows[0] as Record<string, string>)?.count ?? \"0\",\n 10\n );\n\n return {\n data: dataResult.rows as unknown as HistoryEntry[],\n total\n };\n }\n\n /**\n * Fetch a single history entry by ID.\n */\n async fetchHistoryEntry(historyId: string): Promise<HistoryEntry | null> {\n const result = await this.db.execute(sql`\n SELECT id, table_name, entity_id, action, changed_fields,\n \"values\", previous_values, updated_by, updated_at\n FROM rebase.entity_history\n WHERE id = ${historyId}\n `);\n\n if (result.rows.length === 0) return null;\n return result.rows[0] as unknown as HistoryEntry;\n }\n\n // ───────── Retention / Pruning ─────────\n\n /**\n * Prune history for a single entity: enforce maxEntries and TTL.\n */\n async pruneEntity(tableName: string, entityId: string): Promise<number> {\n let deleted = 0;\n\n // 1. TTL — delete entries older than ttlDays\n const ttlResult = await this.db.execute(sql`\n DELETE FROM rebase.entity_history\n WHERE table_name = ${tableName}\n AND entity_id = ${String(entityId)}\n AND updated_at < NOW() - MAKE_INTERVAL(days => ${this.retention.ttlDays})\n `);\n deleted += ttlResult.rowCount ?? 0;\n\n // 2. Max entries — keep the newest maxEntries, delete the rest\n const maxResult = await this.db.execute(sql`\n DELETE FROM rebase.entity_history\n WHERE id IN (\n SELECT id FROM rebase.entity_history\n WHERE table_name = ${tableName}\n AND entity_id = ${String(entityId)}\n ORDER BY updated_at DESC\n OFFSET ${this.retention.maxEntries}\n )\n `);\n deleted += maxResult.rowCount ?? 0;\n\n return deleted;\n }\n\n /**\n * Global prune: enforce TTL across ALL entities in a single sweep.\n * Intended to be called periodically (e.g. once per hour or daily).\n */\n async pruneExpired(): Promise<number> {\n const result = await this.db.execute(sql`\n DELETE FROM rebase.entity_history\n WHERE updated_at < NOW() - MAKE_INTERVAL(days => ${this.retention.ttlDays})\n `);\n return result.rowCount ?? 0;\n }\n}\n\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","import { sql } from \"drizzle-orm\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { logger } from \"@rebasepro/server-core\";\n\n/**\n * Auto-create the entity history table if it doesn't exist.\n * This runs on startup when history is enabled, following the same\n * pattern as `ensureAuthTablesExist`.\n */\nexport async function ensureHistoryTableExists(db: NodePgDatabase): Promise<void> {\n logger.info(\"🔍 Checking entity history table...\");\n\n try {\n // Create the rebase schema (idempotent — may already exist from auth init)\n await db.execute(sql`CREATE SCHEMA IF NOT EXISTS rebase`);\n\n await db.execute(sql`\n CREATE TABLE IF NOT EXISTS rebase.entity_history (\n id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,\n table_name TEXT NOT NULL,\n entity_id TEXT NOT NULL,\n action TEXT NOT NULL,\n changed_fields TEXT[],\n \"values\" JSONB,\n previous_values JSONB,\n updated_by TEXT,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n )\n `);\n\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_history_entity\n ON rebase.entity_history(table_name, entity_id)\n `);\n\n await db.execute(sql`\n CREATE INDEX IF NOT EXISTS idx_history_time\n ON rebase.entity_history(table_name, entity_id, updated_at DESC)\n `);\n\n logger.info(\"✅ Entity history table ready\");\n } catch (error) {\n logger.error(\"❌ Failed to create entity history table\", { error: error });\n logger.warn(\"⚠️ Continuing without creating history table.\");\n }\n}\n","/**\n * PostgresBootstrapper\n *\n * Implements the `BackendBootstrapper` interface for PostgreSQL.\n */\n\nimport { getTableName, isTable, Relations, sql, Table } from \"drizzle-orm\";\nimport { NodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport { PgEnum, PgTable, getTableConfig } from \"drizzle-orm/pg-core\";\nimport type { RebasePgTable } from \"./types\";\nimport {\n BackendBootstrapper,\n InitializedDriver,\n BootstrappedAuth,\n DatabaseAdmin,\n RealtimeProvider,\n type DataDriver,\n type AuthAdapter,\n EntityCollection,\n PostgresCollection\n} from \"@rebasepro/types\";\nimport { PostgresBackendDriver } from \"./PostgresBackendDriver\";\nimport { RealtimeService } from \"./services/realtimeService\";\nimport { DatabasePoolManager } from \"./databasePoolManager\";\nimport { PostgresCollectionRegistry } from \"./collections/PostgresCollectionRegistry\";\nimport {\n createAuthRoutes,\n requireAuth,\n requireAdmin,\n logger\n} from \"@rebasepro/server-core\";\nimport { ensureAuthTablesExist } from \"./auth/ensure-tables\";\nimport { UserService, PostgresAuthRepository, AuthSchemaTables } from \"./auth/services\";\nimport { createAuthSchema } from \"./schema/auth-schema\";\n\nimport { createEmailService, type EmailConfig, type EmailService } from \"@rebasepro/server-core\";\nimport { createHistoryRoutes } from \"@rebasepro/server-core\";\nimport { HistoryService } from \"./history/HistoryService\";\nimport { ensureHistoryTableExists } from \"./history/ensure-history-table\";\nimport type { Hono } from \"hono\";\nimport type { HonoEnv } from \"@rebasepro/server-core\";\n\nexport interface PostgresDriverConfig {\n connectionString?: string;\n adminConnectionString?: string;\n readConnectionString?: string;\n connection?: unknown;\n schema?: {\n tables?: Record<string, unknown>;\n enums?: Record<string, unknown>;\n relations?: Record<string, unknown>;\n };\n}\n\n/**\n * Opaque internals bag that PostgresBootstrapper stores during `initializeDriver()`\n * and re-uses in subsequent lifecycle hooks.\n */\nexport interface PostgresDriverInternals {\n db: NodePgDatabase<any>;\n readDb?: NodePgDatabase<any>;\n registry: PostgresCollectionRegistry;\n realtimeService: RealtimeService;\n driver: PostgresBackendDriver;\n poolManager?: DatabasePoolManager;\n}\n\n/**\n * Default PostgreSQL bootstrapper.\n *\n * Use it to register Postgres with `initializeRebaseBackend()`:\n * ```typescript\n * initializeRebaseBackend({\n * ...config,\n * bootstrappers: [postgresBootstrapper()]\n * });\n * ```\n */\nexport function createPostgresBootstrapper(pgConfig: PostgresDriverConfig): BackendBootstrapper {\n return {\n type: \"postgres\",\n\n async initializeDriver(config: unknown): Promise<InitializedDriver> {\n // config is passed from coordinator, we merge it with our internal pgConfig if needed\n // Currently config from init.ts is `{ collections, collectionRegistry }`\n const { collections, collectionRegistry } = config as {\n collections?: EntityCollection[];\n collectionRegistry?: unknown;\n };\n\n // Create a fresh registry for this driver\n const registry = new PostgresCollectionRegistry();\n if (collections) {\n registry.registerMultiple(collections);\n logger.info(`📋 [PostgresRegistry] Registered ${registry.getCollections().length} collections: [${registry.getCollections().map(c => c.slug).join(\", \")}]`);\n }\n\n // Register tables\n if (pgConfig.schema?.tables) {\n Object.values(pgConfig.schema.tables).forEach((table) => {\n if (isTable(table)) {\n const tableName = getTableName(table);\n registry.registerTable(table as PgTable, tableName);\n }\n });\n }\n\n if (pgConfig.schema?.enums) registry.registerEnums(pgConfig.schema.enums as Record<string, PgEnum<[string, ...string[]]>>);\n if (pgConfig.schema?.relations) registry.registerRelations(pgConfig.schema.relations as Record<string, Relations>);\n\n // Build schema-aware Drizzle connection\n const mergedSchema: Record<string, unknown> = {\n ...pgConfig.schema?.tables,\n ...(pgConfig.schema?.relations || {})\n };\n const { drizzle: createDrizzle } = await import(\"drizzle-orm/node-postgres\");\n const connection = pgConfig.connection;\n const rawClient = (connection && typeof connection === \"object\" && \"$client\" in connection\n ? (connection as Record<string, unknown>).$client\n : connection) as import(\"pg\").Pool;\n const schemaAwareDb = createDrizzle(rawClient, { schema: mergedSchema });\n\n // Verify connection\n try {\n await schemaAwareDb.execute(sql`SELECT 1`);\n } catch (err) {\n logger.error(\"❌ Failed to connect to PostgreSQL\", { error: err });\n logger.warn(\"⚠️ Continuing without initial database verification. Drizzle/PG will attempt to connect on subsequent queries.\");\n }\n\n // Create services\n const realtimeService = new RealtimeService(schemaAwareDb, registry);\n\n // Initialize read replica connection if configured\n let readDb: import(\"drizzle-orm/node-postgres\").NodePgDatabase<any> | undefined;\n const readUrl = process.env.DATABASE_READ_URL;\n if (readUrl && readUrl !== pgConfig.connectionString) {\n try {\n const { createReadReplicaConnection } = await import(\"./connection\");\n const readResources = createReadReplicaConnection(readUrl, mergedSchema);\n readDb = readResources.db;\n logger.info(\"📖 [PostgresBootstrapper] Read replica connection established\");\n } catch (err) {\n logger.warn(\"⚠️ Could not connect to read replica, falling back to primary for all queries\", { error: err });\n }\n }\n const poolManager = pgConfig.adminConnectionString\n ? new DatabasePoolManager(pgConfig.adminConnectionString)\n : undefined;\n const driver = new PostgresBackendDriver(schemaAwareDb, realtimeService, registry, undefined, poolManager);\n realtimeService.setDataDriver(driver);\n\n // Ensure branch metadata table exists when branching is available\n if (driver.branchService) {\n try {\n await driver.branchService.ensureBranchMetadataTable();\n } catch (err) {\n logger.warn(\"⚠️ Could not initialize branch metadata table\", { error: err });\n }\n }\n\n // Enable cross-instance realtime (opt-in)\n // Prefer DATABASE_DIRECT_URL to bypass PgBouncer for LISTEN/NOTIFY\n const directUrl = process.env.DATABASE_DIRECT_URL || pgConfig.connectionString;\n if (directUrl) {\n try {\n await realtimeService.startListening(directUrl);\n } catch (err) {\n logger.warn(\"⚠️ Cross-instance realtime could not be started\", { error: err });\n }\n }\n\n // ── Startup Schema Validation ────────────────────────────────────\n // One-directional: only checks collections → DB (extra DB tables\n // that aren't mapped to collections are perfectly fine).\n try {\n const registeredCollections = registry.getCollections();\n if (registeredCollections.length > 0) {\n const schemasToCheck = Array.from(new Set(\n registeredCollections.map(c => \"schema\" in c && c.schema ? c.schema : \"public\")\n ));\n const schemasList = schemasToCheck.map(s => `'${s}'`).join(\",\");\n const result = await schemaAwareDb.execute(sql.raw(`\n SELECT table_name, table_schema\n FROM information_schema.tables\n WHERE table_schema IN (${schemasList})\n AND table_type = 'BASE TABLE'\n `));\n const dbTables = new Set(\n (result.rows as Array<{ table_name: string; table_schema: string }>).map(r =>\n r.table_schema === \"public\" ? r.table_name : `${r.table_schema}.${r.table_name}`\n )\n );\n const missing: Array<{ slug: string; table: string }> = [];\n for (const col of registeredCollections) {\n const schemaName = \"schema\" in col && col.schema ? col.schema : \"public\";\n const tableName = registry.hasTableForCollection(\n col.table ?? col.slug\n )\n ? (col.table ?? col.slug)\n : col.slug;\n // Resolve the actual table name the registry stored\n const resolvedTable = registry.getTableNames().find((k) =>\n k === tableName ||\n k === col.slug\n );\n const checkName = resolvedTable ?? tableName;\n const fullCheckName = schemaName === \"public\" ? checkName : `${schemaName}.${checkName}`;\n if (!dbTables.has(fullCheckName)) {\n missing.push({ slug: col.slug,\ntable: checkName });\n }\n }\n if (missing.length > 0) {\n const lines = missing.map(\n m => ` • collection \"${m.slug}\" → table \"${m.table}\"`\n );\n logger.warn([\n \"\",\n \"┌──────────────────────────────────────────────────────────────┐\",\n \"│ ⚠️ SCHEMA DRIFT — Missing tables in database │\",\n \"├──────────────────────────────────────────────────────────────┤\",\n ...lines.map(l => `│ ${l.padEnd(60)}│`),\n \"├──────────────────────────────────────────────────────────────┤\",\n \"│ Run one of: │\",\n \"│ pnpm db:push (dev — fast, no migration files) │\",\n \"│ pnpm db:migrate (prod — creates migration files) │\",\n \"└──────────────────────────────────────────────────────────────┘\",\n \"\"\n ].join(\"\\n\"));\n }\n }\n } catch (err) {\n logger.warn(\"⚠️ Startup schema validation could not run\", {\n error: err instanceof Error ? err.message : String(err)\n });\n }\n\n const internals: PostgresDriverInternals = {\n db: schemaAwareDb,\n readDb,\n registry,\n realtimeService,\n driver,\n poolManager\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 authConfig = config as Record<string, unknown> | undefined;\n if (!authConfig) return undefined;\n\n const internals = driverResult.internals as PostgresDriverInternals;\n const db = internals.db;\n const registry = internals.registry;\n\n // Resolve the auth collection from the explicit config.\n // This replaces the old `registry.getTable(\"users\")` magic string lookup.\n const authCollection = authConfig.collection as EntityCollection | undefined;\n\n // ensureAuthTablesExist works with the collection abstraction — no Drizzle leakage.\n await ensureAuthTablesExist(db, authCollection);\n\n let emailService: EmailService | undefined;\n if (authConfig.email) {\n emailService = createEmailService(authConfig.email as EmailConfig);\n }\n\n // Resolve the Drizzle table for the internal UserService/AuthRepository.\n // These are internal Postgres-specific services that need the Drizzle table reference.\n const tableName = authCollection\n ? (\"table\" in authCollection && typeof authCollection.table === \"string\"\n ? authCollection.table\n : authCollection.slug)\n : undefined;\n const usersTable = tableName\n ? registry.getTable(tableName) as RebasePgTable | undefined\n : undefined;\n\n let usersSchemaName = \"rebase\";\n if (authCollection && \"schema\" in authCollection && typeof authCollection.schema === \"string\") {\n usersSchemaName = authCollection.schema;\n }\n\n const authTables = createAuthSchema(usersSchemaName) as unknown as AuthSchemaTables;\n if (usersTable) {\n authTables.users = usersTable as RebasePgTable;\n }\n\n const userService = new UserService(db, authTables);\n const authRepository = new PostgresAuthRepository(db, authTables);\n\n return { userService,\nroleService: userService,\nemailService,\nauthRepository };\n },\n\n async initializeHistory(config: unknown, driverResult: InitializedDriver): Promise<{ historyService: HistoryService } | undefined> {\n const historyConfig = config as { retention?: number } | boolean | undefined;\n if (!historyConfig) return undefined;\n\n const internals = driverResult.internals as PostgresDriverInternals;\n const db = internals.db;\n\n await ensureHistoryTableExists(db);\n\n const retention = typeof historyConfig === \"object\" && historyConfig !== null ? (historyConfig as { retention?: number }).retention : undefined;\n const historyService = new HistoryService(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 PostgresDriverInternals;\n return internals.realtimeService;\n },\n\n getAdmin(driverResult: InitializedDriver): DatabaseAdmin | undefined {\n const internals = driverResult.internals as PostgresDriverInternals;\n return internals.driver.admin;\n },\n\n mountRoutes(app: unknown, basePath: string, driverResult: InitializedDriver): void {\n // The coordinator handles auth/storage/data routes.\n // This hook is for driver-specific extensions only.\n // Currently Postgres doesn't need additional routes beyond what the coordinator mounts.\n },\n\n async initializeWebsockets(server: unknown, realtimeService: RealtimeProvider, driver: DataDriver, config?: unknown, adapter?: unknown): Promise<void> {\n const { createPostgresWebSocket } = await import(\"./websocket\");\n createPostgresWebSocket(\n server as import(\"http\").Server,\n realtimeService as RealtimeService,\n driver as PostgresBackendDriver,\n config as { requireAuth?: boolean },\n adapter as AuthAdapter | undefined\n );\n }\n };\n}\n","import { DatabaseAdapter, InitializedDriver, RealtimeProvider, DataDriver, DatabaseAdmin, BootstrappedAuth } from \"@rebasepro/types\";\nimport { createPostgresBootstrapper } from \"./PostgresBootstrapper\";\nimport type { PostgresDriverConfig } from \"./PostgresBootstrapper\";\n\n/**\n * Creates a Postgres database adapter for Rebase.\n */\nexport function createPostgresAdapter(pgConfig: PostgresDriverConfig): DatabaseAdapter {\n const bootstrapper = createPostgresBootstrapper(pgConfig);\n\n return {\n type: bootstrapper.type,\n\n async initializeDriver(config) {\n return bootstrapper.initializeDriver(config);\n },\n\n async initializeRealtime(driverResult) {\n if (bootstrapper.initializeRealtime) {\n return bootstrapper.initializeRealtime({}, driverResult);\n }\n return undefined;\n },\n\n async initializeAuth(config, driverResult) {\n if (bootstrapper.initializeAuth) {\n return bootstrapper.initializeAuth(config, driverResult);\n }\n return undefined;\n },\n\n async initializeHistory(config, driverResult) {\n if (bootstrapper.initializeHistory) {\n return bootstrapper.initializeHistory(config, driverResult);\n }\n return undefined;\n },\n\n initializeWebsockets(server, realtimeService, driver, config) {\n if (bootstrapper.initializeWebsockets) {\n return bootstrapper.initializeWebsockets(server, realtimeService, driver, config);\n }\n },\n\n getAdmin(driverResult) {\n if (bootstrapper.getAdmin) {\n return bootstrapper.getAdmin(driverResult);\n }\n return undefined;\n },\n\n mountRoutes(app, basePath, driverResult) {\n if (bootstrapper.mountRoutes) {\n bootstrapper.mountRoutes(app, basePath, driverResult);\n }\n }\n };\n}\n","export * from \"./connection\";\nexport * from \"./interfaces\";\nexport * from \"./PostgresBackendDriver\";\nexport * from \"./databasePoolManager\";\nexport * from \"./schema/auth-schema\";\nexport * from \"./schema/generate-drizzle-schema-logic\";\nexport * from \"./schema/generate-drizzle-schema\";\nexport * from \"./utils/drizzle-conditions\";\nexport * from \"./services/realtimeService\";\nexport * from \"./websocket\";\nexport * from \"./collections/PostgresCollectionRegistry\";\nexport * from \"./services/BranchService\";\nexport * from \"./PostgresBootstrapper\";\nexport * from \"./PostgresAdapter\";\n"],"x_google_ignoreList":[57,67,69],"mappings":"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"}