@rebasepro/common 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/collections/CollectionRegistry.d.ts +16 -16
- package/dist/collections/default-collections.d.ts +1 -1
- package/dist/data/buildRebaseData.d.ts +30 -2
- package/dist/data/buildRoutedRebaseData.d.ts +14 -9
- package/dist/data/filter-dialect.d.ts +18 -4
- package/dist/data/query_builder.d.ts +1 -1
- package/dist/data/resolveDataSource.d.ts +1 -1
- package/dist/data/sort-dialect.d.ts +41 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +569 -159
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +573 -163
- package/dist/index.umd.js.map +1 -1
- package/dist/util/builders.d.ts +19 -56
- package/dist/util/callbacks.d.ts +3 -3
- package/dist/util/collections.d.ts +4 -4
- package/dist/util/entities.d.ts +2 -2
- package/dist/util/filter-operator-resolution.d.ts +32 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_from_path.d.ts +4 -4
- package/dist/util/navigation_utils.d.ts +3 -3
- package/dist/util/parent_references_from_path.d.ts +2 -2
- package/dist/util/permissions.d.ts +6 -6
- package/dist/util/policy/policyToPostgres.d.ts +14 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/relations.d.ts +5 -5
- package/dist/util/resolutions.d.ts +2 -2
- package/package.json +3 -3
- package/src/collections/CollectionRegistry.ts +36 -36
- package/src/data/buildRebaseData.ts +332 -57
- package/src/data/buildRoutedRebaseData.ts +22 -16
- package/src/data/filter-dialect.ts +145 -60
- package/src/data/query_builder.ts +11 -2
- package/src/data/resolveDataSource.ts +1 -1
- package/src/data/sort-dialect.ts +56 -0
- package/src/index.ts +1 -0
- package/src/util/builders.ts +25 -99
- package/src/util/callbacks.ts +8 -8
- package/src/util/collections.ts +4 -4
- package/src/util/entities.ts +4 -4
- package/src/util/filter-operator-resolution.ts +81 -0
- package/src/util/index.ts +1 -0
- package/src/util/navigation_from_path.ts +4 -4
- package/src/util/navigation_utils.ts +8 -8
- package/src/util/parent_references_from_path.ts +3 -3
- package/src/util/permissions.test.ts +2 -2
- package/src/util/permissions.ts +7 -7
- package/src/util/policy/evaluatePolicy.ts +6 -0
- package/src/util/policy/policyToPostgres.ts +90 -10
- package/src/util/references.ts +2 -2
- package/src/util/relations.ts +12 -12
- package/src/util/resolutions.ts +5 -5
package/dist/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","names":[],"sources":["../src/util/common.ts","../src/util/entities.ts","../src/util/collections.ts","../src/util/enums.ts","../src/util/paths.ts","../src/util/relations.ts","../src/util/resolutions.ts","../src/util/policy/sqlToPolicy.ts","../src/util/policy/securityRuleToConditions.ts","../src/util/policy/policyToPostgres.ts","../src/util/policy/evaluatePolicy.ts","../src/util/permissions.ts","../src/util/references.ts","../src/util/navigation_utils.ts","../src/util/navigation_from_path.ts","../src/util/parent_references_from_path.ts","../src/util/builders.ts","../src/util/storage.ts","../src/util/callbacks.ts","../src/util/conditions.ts","../src/data/resolveDataSource.ts","../src/collections/CollectionRegistry.ts","../src/collections/default-collections.ts","../src/data/query_builder.ts","../src/data/filter-dialect.ts","../src/data/buildRebaseData.ts","../src/data/buildRoutedRebaseData.ts","../src/table-classification.ts"],"sourcesContent":["export const DEFAULT_ONE_OF_TYPE = \"type\"\nexport const DEFAULT_ONE_OF_VALUE = \"value\"\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 {\n DefaultSelectedViewBuilder,\n DefaultSelectedViewParams,\n EntityCollection,\n Properties,\n Property\n} from \"@rebasepro/types\";\nimport { isPropertyBuilder } from \"./entities\";\n\nexport function sortProperties<M extends Record<string, unknown>>(properties: Properties, propertiesOrder?: string[]): Properties {\n try {\n const propertiesKeys = Object.keys(properties);\n // If no propertiesOrder, just use the original keys order\n if (!propertiesOrder || propertiesOrder.length === 0) {\n return propertiesKeys\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n }\n\n // Filter propertiesOrder to only include TOP-LEVEL property keys that exist\n // (ignore nested keys like \"data.mode\" - they are for column ordering, not property filtering)\n const validOrderKeys = (propertiesOrder as string[]).filter(key => {\n // Only include top-level keys (no dots) that exist in properties\n return !key.includes(\".\") && properties[key];\n });\n\n // Track which properties we've processed\n const processedKeys = new Set<string>(validOrderKeys);\n\n // Build result starting with ordered properties\n const orderedResult = validOrderKeys\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n\n // Append any properties that were NOT in propertiesOrder (so they don't disappear!)\n const missingProperties = propertiesKeys\n .filter(key => !processedKeys.has(key))\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n\n return { ...orderedResult,\n...missingProperties };\n } catch (e) {\n console.error(\"Error sorting properties\", e);\n return properties;\n }\n}\n\nexport function resolveDefaultSelectedView(\n defaultSelectedView: string | DefaultSelectedViewBuilder | undefined,\n params: DefaultSelectedViewParams\n) {\n if (!defaultSelectedView) {\n return undefined;\n } else if (typeof defaultSelectedView === \"string\") {\n return defaultSelectedView;\n } else {\n return defaultSelectedView(params);\n }\n}\n\n\nexport function getLocalChangesBackup(collection: EntityCollection) {\n if (!collection.localChangesBackup) {\n return \"manual_apply\";\n }\n\n return collection.localChangesBackup;\n}\n\n/**\n * Returns the primary keys for an entity collection by inspecting the properties\n * and finding any properties with `isId`.\n * Fallbacks to `[\"id\"]` if no properties are marked as `isId: true`.\n * @param collection\n */\nexport function getPrimaryKeys<M extends Record<string, unknown>>(collection: EntityCollection<M>): Extract<keyof M, string>[] {\n const properties = collection.properties;\n if (!properties) {\n return [\"id\"] as Extract<keyof M, string>[];\n }\n const ids = Object.entries(properties)\n .filter(([key, prop]) => typeof prop === \"object\" && prop !== null && \"isId\" in prop && Boolean(prop.isId))\n .map(([key]) => key);\n\n if (ids.length > 0) {\n return ids as Extract<keyof M, string>[];\n }\n return [\"id\"] as Extract<keyof M, string>[];\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","export const COLLECTION_PATH_SEPARATOR = \"::\";\n\n/**\n * Remove the entity ids from a given path\n * `products/B44RG6APH/locales` => `products::locales`\n * @param path\n */\nexport function stripCollectionPath(path: string): string {\n return segmentsToStrippedPath(fullPathToCollectionSegments(path));\n}\n\nexport function segmentsToStrippedPath(paths: string[]) {\n if (paths.length === 1)\n return paths[0];\n return paths.reduce((a, b) => `${a}${COLLECTION_PATH_SEPARATOR}${b}`);\n}\n\n/**\n * Extract the collection path routes\n * `products/B44RG6APH/locales` => [`products`, `locales`]\n * @param path\n */\nexport function fullPathToCollectionSegments(path: string): string[] {\n return path\n .split(\"/\")\n .filter((e, i) => i % 2 === 0);\n}\n","import { 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.engine).supportsRelations ? (targetCollection.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.engine).supportsRelations ? (targetCollection.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.engine).supportsRelations) return {};\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 (collection.relations) {\n collection.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.engine).supportsRelations) {\n return collection.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 EntityCollection,\n EnumValueConfig,\n EnumValues,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty,\n getDataSourceCapabilities,\n getDeclaredSubcollections\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 const declaredSubcollections = getDeclaredSubcollections(collection);\n if (getDataSourceCapabilities(collection.engine).supportsSubcollections && declaredSubcollections) {\n return declaredSubcollections() ?? [];\n }\n\n if (getDataSourceCapabilities(collection.engine).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 { PolicyExpression, policy } from \"@rebasepro/types\";\n\n/**\n * A tiny, regex-based SQL \"parser\" for security rules.\n *\n * This is NOT a full SQL parser. It is designed to handle the subset of SQL\n * commonly used in `USING` and `WITH CHECK` clauses, enough to drive the\n * optimistic client-side UI decision.\n *\n * It handles:\n * - `field = 'literal'`\n * - `field != 'literal'`\n * - `field = current_setting('app.user_id')`\n * - `A AND B`\n * - `true`\n * - `IN (...)` (as optimistic true)\n *\n * For anything it doesn't understand, it returns a `raw` expression, which\n * the evaluator treats as \"unknown\" (and usually optimistic true).\n */\nexport function sqlToPolicy(sql: string): PolicyExpression {\n const trimmed = sql.trim();\n\n if (trimmed.toLowerCase() === \"true\") return policy.true();\n if (trimmed.toLowerCase() === \"false\") return policy.false();\n\n // Handle roles overlap (&&)\n // Matches: string_to_array(auth.roles(), ',') && ARRAY['admin', 'editor']\n const overlapMatch = trimmed.match(/^string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*&&\\s*ARRAY\\s*\\[(.+)\\]$/i);\n if (overlapMatch) {\n const roles = overlapMatch[1].split(\",\").map(s => s.trim().replace(/^'|'$/g, \"\"));\n return policy.rolesOverlap(roles);\n }\n\n // Handle roles containment (@>)\n // Matches: string_to_array(auth.roles(), ',') @> ARRAY['admin']\n const containMatch = trimmed.match(/^string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*@>\\s*ARRAY\\s*\\[(.+)\\]$/i);\n if (containMatch) {\n const roles = containMatch[1].split(\",\").map(s => s.trim().replace(/^'|'$/g, \"\"));\n return policy.rolesContain(roles);\n }\n\n // Handle OR\n if (trimmed.toUpperCase().includes(\" OR \")) {\n const parts = trimmed.split(/ OR /i);\n return policy.or(...parts.map(sqlToPolicy));\n }\n\n // Handle AND (very basic split, doesn't handle nested parens properly)\n if (trimmed.toUpperCase().includes(\" AND \")) {\n const parts = trimmed.split(/ AND /i);\n return policy.and(...parts.map(sqlToPolicy));\n }\n\n // Handle = and !=\n const match = trimmed.match(/^(.+?)\\s*(!?=)\\s*(.+)$/);\n if (match) {\n const [, leftStr, op, rightStr] = match;\n const left = parseOperand(leftStr.trim());\n const right = parseOperand(rightStr.trim());\n if (left && right) {\n return policy.compare(left, op === \"=\" ? \"eq\" : \"neq\", right);\n }\n }\n\n // Fallback to raw\n return policy.raw(sql);\n}\n\nfunction parseOperand(str: string) {\n // current_setting('app.user_id') or auth.uid()\n if (/current_setting\\s*\\(\\s*'app\\.user_id'\\s*\\)/i.test(str) || /auth\\.uid\\(\\)/i.test(str)) {\n return policy.authUid();\n }\n\n // Literal string: 'value'\n const stringMatch = str.match(/^'(.+)'$/);\n if (stringMatch) {\n return policy.literal(stringMatch[1]);\n }\n\n // Bare field name\n if (/^\\w+$/.test(str)) {\n return policy.field(str);\n }\n\n return null;\n}\n","import { PolicyExpression, SecurityRule, policy } from \"@rebasepro/types\";\nimport { sqlToPolicy } from \"./sqlToPolicy\";\n\n/**\n * The normalized `USING` / `WITH CHECK` conditions for a single security rule,\n * expressed in the engine-agnostic {@link PolicyExpression} model.\n *\n * A `null` clause means \"this rule contributes no condition for that clause\";\n * consumers apply the default (Postgres denies with `false`).\n */\nexport interface RuleConditions {\n usingExpr: PolicyExpression | null;\n withCheckExpr: PolicyExpression | null;\n}\n\n/**\n * Desugars a {@link SecurityRule} — its `access`/`ownerField`/`roles` shortcuts,\n * structured `condition`/`check`, and raw `using`/`withCheck` — into a single\n * normalized {@link PolicyExpression} pair.\n *\n * **This is the linchpin against drift:** both the Postgres DDL generators and\n * the client-side evaluator consume this one function, so there is exactly one\n * definition of what a rule means. In particular, application `roles` are folded\n * into the expression here (AND'd with the base condition, matching how Postgres\n * generates the clause) rather than being handled separately by each consumer.\n */\nexport function securityRuleToConditions(rule: SecurityRule): RuleConditions {\n return {\n usingExpr: withRoles(baseUsing(rule), rule),\n withCheckExpr: withRoles(baseWithCheck(rule), rule)\n };\n}\n\nfunction baseUsing(rule: SecurityRule): PolicyExpression | null {\n if (rule.condition) return rule.condition;\n if (rule.using != null) return sqlToPolicy(rule.using);\n if (rule.access === \"public\") return policy.true();\n if (rule.ownerField) return policy.compare(policy.field(rule.ownerField), \"eq\", policy.authUid());\n return null;\n}\n\nfunction baseWithCheck(rule: SecurityRule): PolicyExpression | null {\n if (rule.check) return rule.check;\n if (rule.withCheck != null) return sqlToPolicy(rule.withCheck);\n // No explicit WITH CHECK → fall back to the USING condition, matching\n // PostgreSQL's own default behavior.\n return baseUsing(rule);\n}\n\n/**\n * AND the base condition with an application-role check, or produce a roles-only\n * condition when there is no base. Mirrors the Postgres generator so that a\n * role-scoped restrictive rule denies exactly the same set of users on both\n * sides.\n */\nfunction withRoles(base: PolicyExpression | null, rule: SecurityRule): PolicyExpression | null {\n if (!rule.roles || rule.roles.length === 0) return base;\n const rolesExpr = policy.rolesOverlap(rule.roles);\n if (rule.mode === \"restrictive\") {\n // Restrictive rule: applies ONLY if user has the roles.\n // If user DOES NOT have the roles, they are NOT restricted (passes).\n // If user HAS the roles, they must pass the base condition.\n // Logical equivalent: NOT(roles) OR base\n return base ? policy.or(policy.not(rolesExpr), base) : policy.not(rolesExpr);\n }\n return base ? policy.and(base, rolesExpr) : rolesExpr;\n}\n","import { EntityCollection, PolicyExpression, PolicyOperand, PolicyCompareOperator, Property } from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\n\n/**\n * Compiles a {@link PolicyExpression} to a PostgreSQL boolean SQL string,\n * suitable for a `USING (...)` / `WITH CHECK (...)` clause.\n *\n * This is one of the two consumers of the shared policy model (the other being\n * {@link evaluatePolicy}); the Postgres schema generators call it so that DDL\n * and the admin UI derive from the exact same expression.\n */\nexport function policyToPostgres(expr: PolicyExpression, collection?: EntityCollection): string {\n switch (expr.kind) {\n case \"true\":\n return \"true\";\n case \"false\":\n return \"false\";\n case \"and\":\n return expr.operands.length === 0\n ? \"true\"\n : expr.operands.map(o => `(${policyToPostgres(o, collection)})`).join(\" AND \");\n case \"or\":\n return expr.operands.length === 0\n ? \"false\"\n : expr.operands.map(o => `(${policyToPostgres(o, collection)})`).join(\" OR \");\n case \"not\":\n // Render the common `auth.uid() IS NULL` (unauthenticated) form directly.\n if (expr.operand.kind === \"authenticated\") return \"auth.uid() IS NULL\";\n return `NOT (${policyToPostgres(expr.operand, collection)})`;\n case \"compare\":\n return `${operandToSql(expr.left, collection)} ${COMPARE_SQL[expr.op]} ${operandToSql(expr.right, collection)}`;\n case \"rolesOverlap\":\n return `string_to_array(auth.roles(), ',') && ${rolesArraySql(expr.roles)}`;\n case \"rolesContain\":\n return `string_to_array(auth.roles(), ',') @> ${rolesArraySql(expr.roles)}`;\n case \"authenticated\":\n return \"auth.uid() IS NOT NULL\";\n case \"raw\":\n // Full-power escape hatch: `{column}` references resolve to the bare\n // column name (matching the previous raw-SQL behavior).\n return expr.sql.replace(/\\{(\\w+)\\}/g, (_, col) => col);\n }\n}\n\nconst COMPARE_SQL: Record<PolicyCompareOperator, string> = {\n eq: \"=\",\n neq: \"!=\",\n lt: \"<\",\n lte: \"<=\",\n gt: \">\",\n gte: \">=\"\n};\n\nfunction operandToSql(operand: PolicyOperand, collection?: EntityCollection): string {\n switch (operand.kind) {\n case \"field\":\n return resolveColumnName(operand.name, collection);\n case \"literal\":\n return quoteLiteral(operand.value);\n case \"authUid\":\n return \"auth.uid()\";\n case \"authRoles\":\n return \"string_to_array(auth.roles(), ',')\";\n }\n}\n\nfunction resolveColumnName(propName: string, collection?: EntityCollection): string {\n const prop = collection?.properties?.[propName] as Property | undefined;\n if (prop && \"columnName\" in prop && typeof (prop as { columnName?: unknown }).columnName === \"string\") {\n return (prop as { columnName: string }).columnName;\n }\n return toSnakeCase(propName);\n}\n\nfunction quoteLiteral(value: string | number | boolean | null): string {\n if (value === null) return \"NULL\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\") return String(value);\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\n/** Sorted, single-quoted `ARRAY['a','b']` — matches the generators' output. */\nfunction rolesArraySql(roles: string[]): string {\n return `ARRAY[${[...roles].sort().map(r => `'${r}'`).join(\",\")}]`;\n}\n","import { Entity, PolicyCompareOperator, PolicyExpression, PolicyOperand } from \"@rebasepro/types\";\n\n/**\n * Result of evaluating a policy client-side. `\"unknown\"` means the expression\n * could not be decided without more information — either a raw-SQL escape-hatch\n * node (which the client deliberately never guesses) or a row-column reference\n * with no entity in hand (e.g. list-level gating). Callers decide how to resolve\n * `\"unknown\"`: fail-closed for an enforcement decision, optimistic for pure\n * visibility gating.\n */\nexport type TriState = boolean | \"unknown\";\n\n/**\n * Context for {@link evaluatePolicy}: the acting user (or none) and the row\n * being evaluated (or none, for collection-level gating).\n */\nexport interface PolicyEvalContext {\n /** The current user's id, or null/undefined when unauthenticated. */\n uid?: string | null;\n /** The current user's application roles. */\n roles?: string[];\n /** The row being evaluated, or null when no specific row is available. */\n entity: Entity | null;\n}\n\n/**\n * Evaluates a {@link PolicyExpression} against a user + row, using three-valued\n * (Kleene) logic so that `\"unknown\"` sub-results propagate soundly.\n *\n * This is the JavaScript twin of {@link policyToPostgres}: both derive from the\n * same expression, so the admin UI matches database enforcement by construction\n * for every non-raw rule.\n */\nexport function evaluatePolicy(expr: PolicyExpression, ctx: PolicyEvalContext): TriState {\n switch (expr.kind) {\n case \"true\":\n return true;\n case \"false\":\n return false;\n case \"and\":\n return kleeneAnd(expr.operands.map(o => evaluatePolicy(o, ctx)));\n case \"or\":\n return kleeneOr(expr.operands.map(o => evaluatePolicy(o, ctx)));\n case \"not\":\n return kleeneNot(evaluatePolicy(expr.operand, ctx));\n case \"compare\":\n return evaluateCompare(expr.op, expr.left, expr.right, ctx);\n case \"rolesOverlap\": {\n const userRoles = ctx.roles ?? [];\n return expr.roles.some(r => r === \"public\" || userRoles.includes(r));\n }\n case \"rolesContain\": {\n const userRoles = ctx.roles ?? [];\n return expr.roles.every(r => r === \"public\" || userRoles.includes(r));\n }\n case \"authenticated\":\n return ctx.uid != null;\n case \"raw\":\n // Arbitrary SQL cannot be evaluated client-side — never guess.\n return \"unknown\";\n }\n}\n\n// ── Three-valued logic ───────────────────────────────────────────────\n\nfunction kleeneAnd(values: TriState[]): TriState {\n if (values.some(v => v === false)) return false;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return true;\n}\n\nfunction kleeneOr(values: TriState[]): TriState {\n if (values.some(v => v === true)) return true;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return false;\n}\n\nfunction kleeneNot(value: TriState): TriState {\n if (value === \"unknown\") return \"unknown\";\n return !value;\n}\n\n// ── Comparison ───────────────────────────────────────────────────────\n\ntype ResolvedOperand = { known: false } | { known: true; value: unknown };\n\nfunction resolveOperand(operand: PolicyOperand, ctx: PolicyEvalContext): ResolvedOperand {\n switch (operand.kind) {\n case \"literal\":\n return { known: true, value: operand.value };\n case \"authUid\":\n return { known: true, value: ctx.uid ?? null };\n case \"authRoles\":\n return { known: true, value: ctx.roles ?? [] };\n case \"field\":\n // Can't resolve a row column without the row.\n if (!ctx.entity) return { known: false };\n return { known: true, value: ctx.entity.values[operand.name] };\n }\n}\n\nfunction evaluateCompare(\n op: PolicyCompareOperator,\n left: PolicyOperand,\n right: PolicyOperand,\n ctx: PolicyEvalContext\n): TriState {\n const l = resolveOperand(left, ctx);\n const r = resolveOperand(right, ctx);\n if (!l.known || !r.known) return \"unknown\";\n\n const a = l.value;\n const b = r.value;\n\n if (a === null || b === null) {\n if (op === \"eq\") return false;\n if (op === \"neq\") return true;\n return \"unknown\";\n }\n\n if (op === \"eq\") return a === b;\n if (op === \"neq\") return a !== b;\n\n if (typeof a === \"string\" && typeof b === \"string\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n if (typeof a === \"bigint\" && typeof b === \"bigint\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n return \"unknown\";\n}\n","import { Entity, EntityCollection, getDataSourceCapabilities, SecurityOperation, SecurityRule, User } from \"@rebasepro/types\";\nimport { securityRuleToConditions } from \"./policy/securityRuleToConditions\";\nimport { evaluatePolicy, PolicyEvalContext, TriState } from \"./policy/evaluatePolicy\";\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\n/**\n * How to resolve a policy result that cannot be decided client-side (a raw-SQL\n * escape-hatch rule, or a row-column reference with no row in hand).\n *\n * - `\"allow\"` (default): optimistic — used for admin-UI gating, where Postgres\n * remains the authoritative gate and hiding a working action is worse than\n * showing one the server may reject.\n * - `\"deny\"`: fail-closed — used by real enforcement callers (e.g. a driver\n * applying policies in-process), so an undecidable rule never silently allows.\n */\nexport type UnknownResolution = \"allow\" | \"deny\";\n\nexport interface CheckOperationOptions {\n onUnknown?: UnknownResolution;\n}\n\n/** Combine clause results with AND under three-valued (Kleene) logic. */\nfunction kleeneAnd(values: TriState[]): TriState {\n if (values.some(v => v === false)) return false;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return true;\n}\n\n/** The operations a rule covers, mirroring the Postgres generator's resolution. */\nfunction ruleOperations(rule: SecurityRule): SecurityOperation[] {\n return rule.operations && rule.operations.length > 0\n ? rule.operations\n : [rule.operation ?? \"all\"];\n}\n\nfunction ruleApplies(rule: SecurityRule, targetOperation: SecurityOperation): boolean {\n const ops = ruleOperations(rule);\n return ops.includes(targetOperation) || ops.includes(\"all\");\n}\n\n/**\n * Evaluate a single rule for one operation, returning a tri-state.\n *\n * A `null` clause (the rule contributes no condition for a required clause)\n * denies — matching Postgres, which emits `USING (false)` / `WITH CHECK (false)`\n * in that case. USING applies to SELECT/UPDATE/DELETE; WITH CHECK to\n * INSERT/UPDATE; both must pass for UPDATE.\n */\nfunction evaluateRuleForOperation(rule: SecurityRule, ctx: PolicyEvalContext, targetOperation: SecurityOperation): TriState {\n const { usingExpr, withCheckExpr } = securityRuleToConditions(rule);\n const clause = (expr: typeof usingExpr): TriState => expr === null ? false : evaluatePolicy(expr, ctx);\n\n const needsUsing = targetOperation !== \"insert\";\n const needsWithCheck = targetOperation === \"insert\" || targetOperation === \"update\";\n\n const results: TriState[] = [];\n if (needsUsing) results.push(clause(usingExpr));\n if (needsWithCheck) results.push(clause(withCheckExpr));\n return kleeneAnd(results);\n}\n\nfunction resolveTriState(value: TriState, onUnknown: UnknownResolution): boolean {\n if (value === \"unknown\") return onUnknown === \"allow\";\n return value;\n}\n\n/**\n * Decide whether an operation is permitted for a user on a (possibly null) row,\n * by evaluating the collection's security rules with the shared policy model —\n * the same model compiled to Postgres RLS DDL, so the decision matches database\n * enforcement for every non-raw rule.\n *\n * @param options.onUnknown how to treat rules that cannot be decided\n * client-side (raw SQL, or row predicates with no row). Defaults to `\"allow\"`\n * for optimistic UI gating; enforcement callers should pass `\"deny\"`.\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: SecurityOperation,\n options?: CheckOperationOptions\n): boolean {\n const onUnknown = options?.onUnknown ?? \"allow\";\n const securityRules = getDataSourceCapabilities(collection.engine).supportsRLS ? collection.securityRules : undefined;\n if (!securityRules || securityRules.length === 0) {\n return true;\n }\n\n const applicableRules = securityRules.filter((r: SecurityRule) => ruleApplies(r, targetOperation));\n if (applicableRules.length === 0) return false;\n\n const ctx: PolicyEvalContext = {\n uid: authContext.user?.uid,\n roles: authContext.user?.roles ?? [],\n entity\n };\n\n let grantedByPermissive = false;\n let deniedByRestrictive = false;\n let hasPermissive = false;\n\n for (const rule of applicableRules) {\n const mode = rule.mode || \"permissive\";\n const passed = resolveTriState(evaluateRuleForOperation(rule, ctx, targetOperation), onUnknown);\n\n if (mode === \"restrictive\") {\n if (!passed) {\n deniedByRestrictive = true;\n break;\n }\n } else {\n hasPermissive = true;\n if (passed) grantedByPermissive = true;\n }\n }\n\n if (deniedByRestrictive) return false;\n return hasPermissive ? grantedByPermissive : false;\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 } from \"@rebasepro/types\";\n\nexport function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: EntityCollection<M>): string | undefined {\n\n // find first storage property of type image\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // alternatively, look for the first array of images\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // also check for URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.ui?.url === \"image\") {\n return key;\n }\n }\n // and arrays of URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && property.of && !Array.isArray(property.of) && property.of.type === \"string\" && property.of.ui?.url === \"image\") {\n return key;\n }\n }\n // fallback: any storage property without explicit acceptedFiles (e.g. a generic \"picture\" field)\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage && !property.storage.acceptedFiles) {\n return key;\n }\n }\n // fallback: any array of storage properties without explicit acceptedFiles\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage && !property.of.storage.acceptedFiles) {\n return key;\n }\n }\n return undefined;\n}\n","import { EntityCollection } from \"@rebasepro/types\";\n\nimport { getSubcollections } from \"./resolutions\";\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n\nexport function addInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s;\n else return `/${s}`;\n}\n\nexport function getLastSegment(path: string) {\n const cleanPath = removeInitialAndTrailingSlashes(path);\n if (cleanPath.includes(\"/\")) {\n const segments = cleanPath.split(\"/\");\n return segments[segments.length - 1];\n }\n return cleanPath;\n}\n\nexport function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string {\n let remainingPath = removeInitialAndTrailingSlashes(path);\n if (!remainingPath) {\n return \"\";\n }\n\n let currentCollections: EntityCollection[] | undefined = allCollections;\n const resolvedPathParts: string[] = [];\n\n while (remainingPath.length > 0) {\n if (!currentCollections || currentCollections.length === 0) {\n // We have remaining path segments but no more collections to match against\n console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath);\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n let foundMatch = false;\n // Sort potential matches by length descending to prioritize longer matches (e.g., \"a/b\" over \"a\")\n const potentialMatches: { col: EntityCollection; match: string; }[] = currentCollections\n .flatMap(col => [{\n col,\n match: col.slug\n }])\n .filter(p => p.match && remainingPath.startsWith(p.match))\n .sort((a, b) => b.match.length - a.match.length);\n\n if (potentialMatches.length > 0) {\n const {\n col: foundCollection,\n match: matchString\n } = potentialMatches[0];\n\n resolvedPathParts.push(foundCollection.slug); // Use the defined path\n remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));\n\n // Check if we are at the end of the path\n if (remainingPath.length === 0) {\n foundMatch = true;\n break; // Path ends with a collection segment\n }\n\n // The next segment must be an entity ID\n const idSeparatorIndex = remainingPath.indexOf(\"/\");\n let entityId: string | number;\n if (idSeparatorIndex > -1) {\n entityId = remainingPath.substring(0, idSeparatorIndex);\n remainingPath = remainingPath.substring(idSeparatorIndex + 1);\n } else {\n // This should not happen if the original path is valid (odd segments)\n // but handle it defensively: assume the rest is the ID\n entityId = remainingPath;\n remainingPath = \"\";\n console.warn(`resolveCollectionPathIds: Path seems to end with an entity ID \"${entityId}\" instead of a collection segment in original path \"${path}\". This might indicate an invalid input path.`);\n // Even if it ends here, we still need to push the ID\n }\n\n resolvedPathParts.push(entityId); // Append entity ID\n currentCollections = getSubcollections(foundCollection); // Move to subcollections\n foundMatch = true;\n\n if (!currentCollections && remainingPath.length > 0) {\n // Warn if the path continues but no subcollections were defined\n console.warn(`resolveCollectionPathIds: Path continues after entity ID \"${entityId}\", but no subcollections are defined for the preceding collection \"${foundCollection.slug}\" in path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n }\n\n if (!foundMatch) {\n // Collection definition not found for the start of the remaining path\n console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n }\n\n return resolvedPathParts.join(\"/\");\n}\n\n/**\n * Find the corresponding view at any depth for a given path.\n * Note that path or segments of the paths can be collection aliases.\n * @param slugOrPath\n * @param collections\n */\nexport function getCollectionBySlugWithin(slugOrPath: string, collections: EntityCollection[]): EntityCollection | undefined {\n\n const subpaths = removeInitialAndTrailingSlashes(slugOrPath).split(\"/\");\n if (subpaths.length % 2 === 0) {\n throw Error(`getCollectionBySlug: Collection paths must have an odd number of segments: ${slugOrPath}`);\n }\n\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n let result: EntityCollection | undefined;\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n const navigationEntry = collections && collections\n .sort((a, b) => (a.slug ?? \"\").localeCompare(b.slug ?? \"\"))\n .find((entry) => entry.slug === subpathCombination);\n\n if (navigationEntry) {\n\n if (subpathCombination === slugOrPath) {\n result = navigationEntry;\n } else if (getSubcollections(navigationEntry).length > 0) {\n const newPath = slugOrPath.replace(subpathCombination, \"\").split(\"/\").slice(2).join(\"/\");\n if (newPath.length > 0)\n result = getCollectionBySlugWithin(newPath, getSubcollections(navigationEntry));\n }\n }\n if (result) break;\n }\n return result;\n}\n\n/**\n * Get the subcollection combinations from a path:\n * \"sites/es/locales\" => [\"sites/es/locales\", \"sites\"]\n * @param subpaths\n */\nexport function getCollectionPathsCombinations(subpaths: string[]): string[] {\n const entries = subpaths.length > 0 && subpaths.length % 2 === 0 ? subpaths.splice(0, subpaths.length - 1) : subpaths;\n\n const length = entries.length;\n const result: string[] = [];\n for (let i = length; i > 0; i = i - 2) {\n result.push(entries.slice(0, i).join(\"/\"));\n }\n return result;\n}\n","import { EntityCollection } from \"@rebasepro/types\";\ntype EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = { key: string; [key: string]: unknown };\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"./resolutions\";\n\nexport type NavigationViewInternal<M extends Record<string, unknown> = Record<string, unknown>> =\n | NavigationViewEntityInternal<M>\n | NavigationViewCollectionInternal<M>\n | NavigationViewEntityCustomInternal<M>;\n\nexport interface NavigationViewEntityInternal<M extends Record<string, unknown>> {\n type: \"entity\";\n entityId: string | number;\n slug: string;\n path: string;\n parentCollection: EntityCollection<M>;\n}\n\nexport interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {\n type: \"collection\";\n id: string;\n slug: string;\n path: string;\n collection: EntityCollection<M>;\n}\n\nexport interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {\n type: \"custom_view\";\n slug: string;\n path: string;\n entityId: string | number;\n view: EntityCustomView<M>;\n}\n\nexport function getNavigationEntriesFromPath(props: {\n path: string,\n collections: EntityCollection[] | undefined,\n currentFullPath?: string,\n contextEntityViews?: EntityCustomView[]\n}): NavigationViewInternal[] {\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: NavigationViewInternal[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug)\n : collection.slug;\n result.push({\n type: \"collection\",\n id: collection.slug,\n slug: collectionPath,\n path: collectionPath,\n collection\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({\n type: \"entity\",\n entityId,\n slug: collectionPath,\n path,\n parentCollection: collection\n });\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 const entityViews = collection.entityViews;\n const customView = entityViews && entityViews\n .map((entry) => resolveEntityView(entry, props.contextEntityViews))\n .filter((v): v is EntityCustomView => v != null)\n .find((entry) => entry.key === newPath);\n const subcollections = getSubcollections(collection);\n if (customView) {\n result.push({\n type: \"custom_view\",\n slug: collectionPath,\n entityId: entityId,\n path: path + \"/\" + customView.key,\n view: customView\n });\n } else if (subcollections) {\n result.push(...getNavigationEntriesFromPath({\n path: newPath,\n collections: subcollections,\n currentFullPath: path,\n contextEntityViews: props.contextEntityViews\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n\nfunction resolveEntityView(entityView: string | EntityCustomView, contextEntityViews?: EntityCustomView[]): EntityCustomView | undefined {\n if (typeof entityView === \"string\") {\n return contextEntityViews?.find((entry) => entry.key === entityView);\n } else {\n return entityView;\n }\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 {\n AdditionalFieldDelegate,\n ArrayProperty,\n BooleanProperty,\n DateProperty,\n EntityCallbacks,\n EntityCollection,\n EnumValueConfig,\n EnumValues,\n FirebaseCollection,\n FirebaseProperties,\n GeopointProperty,\n InferEntityType,\n MapProperty,\n MongoDBCollection,\n MongoProperties,\n NumberProperty,\n PostgresCollection,\n PostgresProperties,\n Properties,\n Property,\n ReferenceProperty,\n StringProperty,\n User\n} from \"@rebasepro/types\";\n\n\n/**\n * Identity function we use to defeat the type system of Typescript and build\n * collection views with all its properties\n * @param collection\n * @group Builder\n */\nexport function buildCollection<\n M extends Record<string, unknown> = Record<string, unknown>,\n USER extends User = User>\n (\n collection: EntityCollection<M, USER>\n ): EntityCollection<M, USER> {\n return collection;\n}\n\n// ── defineCollection ─────────────────────────────────────────────────────\n// A smarter builder that uses `const` type-parameter inference (TS 5.0+)\n// to capture literal property types automatically. This gives you\n// autocomplete on `titleProperty`, `sort`, `propertiesOrder`, `fixedFilter`,\n// callbacks, etc. — without writing `as const` or passing manual generics.\n\n/**\n * Define a PostgreSQL-backed collection with full type inference.\n *\n * The `const P` generic captures literal property types from your\n * `properties` object, which enables autocomplete on `titleProperty`,\n * `sort`, `propertiesOrder`, `fixedFilter`, and entity callbacks.\n *\n * @example\n * ```ts\n * const products = defineCollection({\n * name: \"Products\",\n * slug: \"products\",\n * table: \"products\",\n * properties: {\n * name: { name: \"Name\", type: \"string\", validation: { required: true } },\n * price: { name: \"Price\", type: \"number\" },\n * },\n * titleProperty: \"name\", // ✅ autocomplete: \"name\" | \"price\"\n * sort: [\"price\", \"asc\"], // ✅ autocomplete on first element\n * });\n * ```\n *\n * @group Builder\n */\nexport function defineCollection<\n const P extends PostgresProperties,\n USER extends User = User\n>(\n collection: Omit<PostgresCollection<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): PostgresCollection<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Define a Firestore-backed collection with full type inference.\n * @group Builder\n */\nexport function defineCollection<\n const P extends FirebaseProperties,\n USER extends User = User\n>(\n collection: Omit<FirebaseCollection<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): FirebaseCollection<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Define a MongoDB-backed collection with full type inference.\n * @group Builder\n */\nexport function defineCollection<\n const P extends MongoProperties,\n USER extends User = User\n>(\n collection: Omit<MongoDBCollection<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): MongoDBCollection<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Implementation — delegates to the correct overload at the type level.\n * At runtime this is a plain identity function.\n */\nexport function defineCollection(\n collection: EntityCollection\n): EntityCollection {\n return collection;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the property keys.\n * @param property\n * @group Builder\n */\nexport function buildProperty<T, P extends Property = Property>(\n property: P\n):\n P extends StringProperty ? StringProperty :\n P extends NumberProperty ? NumberProperty :\n P extends BooleanProperty ? BooleanProperty :\n P extends DateProperty ? DateProperty :\n P extends GeopointProperty ? GeopointProperty :\n P extends ReferenceProperty ? ReferenceProperty :\n P extends ArrayProperty ? ArrayProperty :\n P extends MapProperty ? MapProperty : never {\n\n // SAFETY: Identity function — P is a subtype of the conditional return type by definition\n return property as unknown as ReturnType<typeof buildProperty<T, P>>;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the properties keys.\n * @param properties\n * @group Builder\n */\nexport function buildProperties<M extends Record<string, unknown>>(\n properties: Properties\n): Properties {\n return properties;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the properties keys.\n * @param propertiesOrBuilder\n * @group Builder\n */\nexport function buildPropertiesOrBuilder<M extends Record<string, unknown>>(\n propertiesOrBuilder: Properties\n): Properties {\n return propertiesOrBuilder;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the properties keys.\n * @param enumValues\n * @group Builder\n */\nexport function buildEnum(\n enumValues: EnumValues\n): EnumValues {\n return enumValues;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the properties keys.\n * @param enumValueConfig\n * @group Builder\n */\nexport function buildEnumValueConfig(\n enumValueConfig: EnumValueConfig\n): EnumValueConfig {\n return enumValueConfig;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and preserve\n * the properties keys.\n * @param callbacks\n * @group Builder\n */\nexport function buildEntityCallbacks<M extends Record<string, unknown> = Record<string, unknown>>(\n callbacks: EntityCallbacks<M>\n): EntityCallbacks<M> {\n return callbacks;\n}\n\n/**\n * Identity function we use to defeat the type system of Typescript and build\n * additional field delegates views with all its properties\n * @param additionalFieldDelegate\n * @group Builder\n */\nexport function buildAdditionalFieldDelegate<M extends Record<string, unknown>, USER extends User = User>(\n additionalFieldDelegate: AdditionalFieldDelegate<M, USER>\n): AdditionalFieldDelegate<M, USER> {\n return additionalFieldDelegate;\n}\n\n\n","import { ArrayProperty, EntityValues, StorageConfig, StorageSource, StorageSourceRegistry, StringProperty, UploadedFileContext } from \"@rebasepro/types\";\nimport { randomString } from \"@rebasepro/utils\";\n\n/**\n * Resolve the {@link StorageSource} to use for a property, given the key\n * referenced by `StorageConfig.storageSource`.\n *\n * Resolution priority:\n * 1. No `sourceKey` → the default source (backward compatible).\n * 2. An explicit {@link StorageSourceRegistry} (e.g. `client.storageRegistry`).\n * 3. A `sources` lookup map (e.g. the `StorageSourcesContext`).\n * 4. Fall back to the default source.\n *\n * Shared by the upload hook, the markdown editor, and the read-only previews\n * so the resolution logic lives in one place.\n *\n * @group Storage\n */\nexport function resolveStorageSource(params: {\n /** Key from `StorageConfig.storageSource`. */\n sourceKey?: string | null;\n /** Built sources keyed by storage-source key (e.g. from context). */\n sources?: Record<string, StorageSource>;\n /** Optional explicit registry — takes precedence over `sources`. */\n registry?: StorageSourceRegistry;\n /** Default source, used when no key is set or the key cannot be resolved. */\n defaultSource: StorageSource;\n}): StorageSource {\n const { sourceKey, sources, registry, defaultSource } = params;\n if (!sourceKey) return defaultSource;\n if (registry) return registry.getOrDefault(sourceKey);\n const fromSources = sources?.[sourceKey];\n if (fromSources) return fromSources;\n return defaultSource;\n}\n\ninterface ResolveFilenameStringParams<M extends Record<string, unknown>> {\n input: string | ((context: UploadedFileContext) => (Promise<string> | string));\n storage: StorageConfig;\n values: EntityValues<M>;\n entityId?: string | number;\n path?: string;\n property: StringProperty | ArrayProperty,\n file: File;\n propertyKey: string;\n}\n\nexport async function resolveStorageFilenameString<M extends Record<string, unknown>>(\n {\n input,\n storage,\n values,\n entityId,\n path,\n property,\n file,\n propertyKey\n }: ResolveFilenameStringParams<M>): Promise<string> {\n let result;\n\n if (typeof input === \"function\") {\n result = await input({\n path,\n entityId,\n values,\n property,\n file,\n storage,\n propertyKey\n });\n if (!result)\n console.warn(\"Storage callback returned empty result. Using default name value\")\n } else {\n result = replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n });\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n\ninterface ResolveStoragePathStringParams<M extends Record<string, unknown>> {\n input: string | ((context: UploadedFileContext) => string);\n storage: StorageConfig;\n values: EntityValues<M>;\n entityId?: string | number;\n path?: string;\n property: StringProperty | ArrayProperty;\n file: File;\n propertyKey: string;\n}\n\nexport function resolveStoragePathString<M extends Record<string, unknown>>(\n {\n input,\n storage,\n values,\n entityId,\n path,\n property,\n file,\n propertyKey\n }: ResolveStoragePathStringParams<M>): string {\n let result;\n if (typeof input === \"function\") {\n result = input({\n path,\n entityId,\n values,\n property,\n file,\n storage,\n propertyKey\n });\n if (!result)\n console.warn(\"Storage callback returned empty result. Using default name value\")\n } else {\n result = replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n });\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n\ninterface Placeholders {\n file: File;\n input: string;\n entityId?: string | number;\n propertyKey: string;\n path?: string;\n}\n\nfunction replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n}: Placeholders) {\n const ext = file.name.split(\".\").pop();\n let result = input\n .replace(\"{propertyKey}\", propertyKey)\n .replace(\"{rand}\", randomString())\n .replace(\"{file}\", file.name)\n .replace(\"{file.type}\", file.type);\n if (entityId) {\n result = result.replace(\"{entityId}\", String(entityId));\n }\n if (path) {\n result = result.replace(\"{path}\", path);\n }\n if (ext) {\n result = result.replace(\"{file.ext}\", ext);\n const name = file.name.replace(`.${ext}`, \"\");\n result = result.replace(\"{file.name}\", name)\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n","import { EntityCallbacks, Properties, RebaseCallContext } from \"@rebasepro/types\";\n\n/**\n * Context passed to entity lifecycle callbacks.\n * @group Models\n */\nexport type EntityCallbackContext = RebaseCallContext;\n\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","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","import {\n DataSourceDefinition,\n ResolvedDataSource,\n DEFAULT_DATA_SOURCE_KEY,\n getDataSourceCapabilities\n} from \"@rebasepro/types\";\n\n/**\n * The subset of a collection needed to resolve its data source. Accepting a\n * structural type (rather than the full `EntityCollection`) keeps this usable\n * from anywhere — frontend router, backend registry, editor — without coupling\n * to the collection union.\n */\nexport interface DataSourceResolvable {\n /** Preferred routing key. */\n dataSource?: string;\n /** Engine type discriminant (set on variant collection types). */\n engine?: string;\n /** Within-engine instance. */\n databaseId?: string;\n}\n\n/** A lookup of data-source definitions by key. */\nexport type DataSourceRegistry = Record<string, DataSourceDefinition>;\n\n/**\n * Build a keyed registry from a list of {@link DataSourceDefinition}s.\n * Later entries win on key collision.\n */\nexport function createDataSourceRegistry(definitions?: DataSourceDefinition[]): DataSourceRegistry {\n const registry: DataSourceRegistry = {};\n for (const def of definitions ?? []) {\n registry[def.key] = def;\n }\n return registry;\n}\n\n/**\n * Resolve the effective data source for a collection — the single source of\n * truth shared by the frontend router, the backend driver registry, and the\n * editor's capability lookups.\n *\n * Resolution order:\n * 1. The routing **key** is `collection.dataSource`, else\n * {@link DEFAULT_DATA_SOURCE_KEY}.\n * 2. If a definition is registered for that key, it provides `engine`,\n * `transport`, and `databaseId`.\n * 3. Otherwise values are synthesized: `engine` from `collection.engine`\n * (or the key, or `\"postgres\"`), `transport` defaults to `\"server\"`,\n * and `databaseId` from the collection.\n *\n * `capabilities` are always derived from the resolved `engine`, so two\n * data sources sharing an engine share capabilities.\n *\n * @param collection the collection (or any object carrying the routing fields)\n * @param registry optional registry of declared data sources\n */\nexport function resolveDataSource(\n collection: DataSourceResolvable | undefined,\n registry?: DataSourceRegistry\n): ResolvedDataSource {\n const key = collection?.dataSource ?? DEFAULT_DATA_SOURCE_KEY;\n const def = registry?.[key];\n\n const engine = def?.engine\n ?? collection?.engine\n ?? (key !== DEFAULT_DATA_SOURCE_KEY ? key : \"postgres\");\n\n const transport = def?.transport ?? \"server\";\n const databaseId = collection?.databaseId ?? def?.databaseId;\n\n return {\n key,\n engine,\n transport,\n databaseId,\n capabilities: getDataSourceCapabilities(engine)\n };\n}\n","import {\n ArrayProperty,\n EntityCallbacks,\n EngineProperties,\n EntityCollection,\n getDataSourceCapabilities,\n getDeclaredSubcollections,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty\n} from \"@rebasepro/types\";\nimport { deepEqual } from \"fast-equals\";\n\nimport {\n enumToObjectEntries,\n findRelation,\n getSubcollections,\n getTableName,\n resolveCollectionRelations,\n sanitizeRelation\n} from \"../util\";\nimport { deepClone, mergeDeep, removeFunctions } from \"@rebasepro/utils\";\nimport { DataSourceRegistry, resolveDataSource } from \"../data/resolveDataSource\";\n\nexport class CollectionRegistry {\n\n /**\n * Declared data sources, used during normalization to resolve each\n * collection's engine (so `dataSource`-only collections get the right\n * capabilities). Empty by default.\n */\n private dataSources: DataSourceRegistry = {};\n\n /**\n * Global lifecycle callbacks applied to every collection.\n * Runs on all data paths (REST, WebSocket, `rebase.data`).\n * Execution order: global → collection → property callbacks.\n */\n private _globalCallbacks?: EntityCallbacks;\n\n /**\n * Set global lifecycle callbacks that apply to every collection.\n * Typically called once during backend initialization.\n */\n setGlobalCallbacks(callbacks: EntityCallbacks): void {\n this._globalCallbacks = callbacks;\n }\n\n /**\n * Get the currently registered global callbacks, if any.\n */\n getGlobalCallbacks(): EntityCallbacks | undefined {\n return this._globalCallbacks;\n }\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[], dataSources?: DataSourceRegistry) {\n if (dataSources) this.dataSources = dataSources;\n if (collections) {\n this.registerMultiple(collections);\n }\n }\n\n /**\n * Provide the declared data sources used to resolve each collection's\n * engine during normalization. Set this before registering collections.\n * Returns true if the registry changed (callers may re-register).\n */\n setDataSources(dataSources: DataSourceRegistry): boolean {\n if (deepEqual(this.dataSources, dataSources)) return false;\n this.dataSources = dataSources ?? {};\n return true;\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 // 0. Resolve and stamp `dataSource` and `engine` on the normalized copy.\n // After this block every normalized collection has both fields set,\n // so downstream code can read them directly without calling\n // `resolveDataSource()`. Only the normalized layer is affected —\n // the raw layer used by the collection editor keeps the author's\n // original fields.\n {\n const resolved = resolveDataSource(result, this.dataSources);\n if (!result.dataSource) (result as { dataSource?: string }).dataSource = resolved.key;\n if (!result.engine) (result as { engine?: string }).engine = resolved.engine;\n }\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;\n const manualRelations = getDataSourceCapabilities(result.engine).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.engine).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 as EngineProperties;\n\n // Populate childCollections from driver-specific fields\n if (!result.childCollections) {\n const capabilities = getDataSourceCapabilities(result.engine);\n const declaredSubcollections = getDeclaredSubcollections(result);\n if (capabilities.supportsSubcollections && declaredSubcollections) {\n result.childCollections = declaredSubcollections;\n } else if (capabilities.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.engine).supportsRelations) {\n throw new Error(`Relation path navigation requires a collection that supports relations, but '${currentCollection.slug}' uses engine '${currentCollection.engine}'`);\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 { defineCollection } from \"../util/builders\";\n\n/**\n * Default users collection.\n *\n * Prepended to the developer's collections array by the admin and server.\n * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers\n * override by defining their own collection with `slug: \"users\"`.\n */\nexport const defaultUsersCollection = defineCollection({\n name: \"Users\",\n singularName: \"User\",\n slug: \"users\",\n auth: true,\n table: \"users\",\n schema: \"rebase\",\n icon: \"Users\",\n group: \"Settings\",\n openEntityMode: \"dialog\",\n disableDefaultActions: [\"copy\"],\n securityRules: [\n { operation: \"select\",\nroles: [\"admin\"] },\n { operations: [\"insert\", \"update\", \"delete\"],\nroles: [\"admin\"] }\n ],\n sort: [\"createdAt\", \"desc\"],\n properties: {\n id: {\n name: \"ID\",\n type: \"string\",\n isId: \"uuid\",\n ui: { readOnly: true }\n },\n email: {\n name: \"Email\",\n type: \"string\",\n validation: { required: true,\nunique: true }\n },\n displayName: {\n name: \"Name\",\n type: \"string\",\n columnName: \"display_name\",\n validation: { required: true }\n },\n photoURL: {\n name: \"Photo URL\",\n type: \"string\",\n columnName: \"photo_url\",\n ui: { url: \"image\" }\n },\n roles: {\n name: \"Roles\",\n type: \"array\",\n columnType: \"text[]\",\n of: {\n name: \"Role\",\n type: \"string\",\n enum: {\n admin: \"Admin\",\n editor: \"Editor\",\n viewer: \"Viewer\"\n }\n }\n },\n passwordHash: {\n name: \"Password Hash\",\n type: \"string\",\n columnName: \"password_hash\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerified: {\n name: \"Email Verified\",\n type: \"boolean\",\n columnName: \"email_verified\",\n defaultValue: false,\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerificationToken: {\n name: \"Email Verification Token\",\n type: \"string\",\n columnName: \"email_verification_token\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerificationSentAt: {\n name: \"Email Verification Sent At\",\n type: \"date\",\n columnName: \"email_verification_sent_at\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n metadata: {\n name: \"Metadata\",\n type: \"map\",\n keyValue: true,\n properties: {},\n defaultValue: {},\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n createdAt: {\n name: \"Created At\",\n type: \"date\",\n columnName: \"created_at\",\n autoValue: \"on_create\",\n ui: { readOnly: true }\n },\n updatedAt: {\n name: \"Updated At\",\n type: \"date\",\n columnName: \"updated_at\",\n autoValue: \"on_update\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n }\n },\n listProperties: [\"displayName\", \"email\", \"roles\", \"createdAt\"],\n propertiesOrder: [\"id\", \"email\", \"displayName\", \"roles\", \"createdAt\"]\n});\n","import { FindParams, Entity, FindResponse, CollectionAccessor, QueryBuilderInterface, WhereFilterOp, 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: WhereFilterOp, 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: WhereFilterOp, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, 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: [WhereFilterOp, 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 [WhereFilterOp, unknown][]).push(condition);\n } else {\n // Convert existing single tuple/value into array of tuples\n let firstCondition: [WhereFilterOp, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [WhereFilterOp, 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, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = `${column}:${direction}`;\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","/**\n * REST wire-format adapter for the unified filter system.\n *\n * This module is the ONLY code in the entire codebase that knows about\n * PostgREST-style dot-syntax strings (`eq.active`, `gt.18`, `in.(a,b)`).\n * Everything else speaks `FilterValues` exclusively.\n *\n * @module\n */\n\nimport {\n WhereFilterOp,\n FilterValues,\n CANONICAL_TO_REST,\n REST_TO_CANONICAL,\n RestFilterOp,\n toCanonicalOp,\n LogicalCondition,\n FilterCondition\n} from \"@rebasepro/types\";\n\n// ---------------------------------------------------------------------------\n// Value coercion (querystring → typed JS values)\n// ---------------------------------------------------------------------------\n\n/**\n * Coerce a raw querystring value to its natural JS type.\n * - `\"true\"` / `\"false\"` → boolean\n * - `\"null\"` → null\n * - Numeric strings → number\n * - Everything else → string (unchanged)\n */\nfunction coerceValue(raw: string): unknown {\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n if (raw === \"null\") return null;\n if (raw !== \"\" && !isNaN(Number(raw))) return Number(raw);\n return raw;\n}\n\n/**\n * Serialize a JS value to its querystring representation.\n */\nfunction stringifyValue(value: unknown): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return String(value);\n return String(value);\n}\n\n// ---------------------------------------------------------------------------\n// Serialize: FilterValues → REST querystring\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a single condition tuple to a PostgREST dot-string.\n *\n * @example\n * serializeTuple([\"==\", \"active\"]) // \"eq.active\"\n * serializeTuple([\"in\", [\"admin\",\"editor\"]]) // \"in.(admin,editor)\"\n * serializeTuple([\">=\", 18]) // \"gte.18\"\n */\nfunction serializeTuple(tuple: [WhereFilterOp, unknown] | unknown): string {\n // If it's already a string, it might be a PostgREST string (with dot)\n // or a raw value (without dot). In both cases, existing tests expect\n // them to be passed through or treated as simple equality if no dot.\n if (typeof tuple === \"string\") {\n if (tuple.includes(\".\")) {\n const dotIndex = tuple.indexOf(\".\");\n const prefix = tuple.substring(0, dotIndex);\n if ((REST_TO_CANONICAL as any)[prefix]) {\n return tuple;\n }\n }\n return tuple;\n }\n\n // If it's NOT a canonical tuple [WhereFilterOp, value], treat as equality.\n if (!Array.isArray(tuple) || tuple.length !== 2 || typeof tuple[0] !== \"string\" || !(CANONICAL_TO_REST as any)[tuple[0]]) {\n return `eq.${stringifyValue(tuple)}`;\n }\n\n const [op, value] = tuple as [WhereFilterOp, unknown];\n const restOp = CANONICAL_TO_REST[op];\n\n if (Array.isArray(value)) {\n const items = value.map(stringifyValue).join(\",\");\n return `${restOp}.(${items})`;\n }\n\n return `${restOp}.${stringifyValue(value)}`;\n}\n\n/**\n * Convert `FilterValues` to a PostgREST-style querystring record.\n *\n * - Single conditions produce a string value.\n * - Multiple conditions on the same field produce a string array (repeated params).\n *\n * @example\n * serializeFilter({ status: [\"==\", \"active\"] })\n * // → { status: \"eq.active\" }\n *\n * serializeFilter({ age: [[\">=\", 18], [\"<\", 65]] })\n * // → { age: [\"gte.18\", \"lt.65\"] }\n */\nexport function serializeFilter(\n filter: FilterValues<string> | Record<string, any>\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n for (const [field, condition] of Object.entries(filter)) {\n if (condition === undefined) continue;\n\n // Multiple conditions on the same field: array of tuples\n // We detect this by checking if the first element is also an array.\n if (Array.isArray(condition) && condition.length > 0 && Array.isArray(condition[0])) {\n result[field] = (condition as any[]).map(serializeTuple);\n } else {\n // Single condition (could be a tuple, a raw value, or an already-serialized string)\n result[field] = serializeTuple(condition);\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Deserialize: REST querystring → FilterValues\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a single PostgREST dot-string into a `[WhereFilterOp, unknown]` tuple.\n *\n * If the string doesn't match a known operator prefix, falls back to\n * `[\"==\", originalString]` (treating the whole string as an equality value).\n */\nfunction deserializeSingle(raw: string): [WhereFilterOp, unknown] {\n const dotIndex = raw.indexOf(\".\");\n if (dotIndex === -1) {\n // No dot → equality on the raw value (coerced)\n return [\"==\", coerceValue(raw)];\n }\n\n const prefix = raw.substring(0, dotIndex);\n const rest = raw.substring(dotIndex + 1);\n\n // Check if the prefix is a known REST operator\n const canonicalOp = (REST_TO_CANONICAL as Record<string, WhereFilterOp | undefined>)[prefix];\n if (!canonicalOp) {\n // Not a known operator (e.g., email \"user@host.com\" or version \"1.2.3\")\n // Treat the entire string as an equality value\n return [\"==\", raw];\n }\n\n // Parse list values: \"(admin,editor)\" → [\"admin\", \"editor\"]\n if (rest.startsWith(\"(\") && rest.endsWith(\")\")) {\n const items = rest.slice(1, -1).split(\",\").map(s => coerceValue(s.trim()));\n return [canonicalOp, items];\n }\n\n return [canonicalOp, coerceValue(rest)];\n}\n\n/**\n * Convert a PostgREST-style querystring record to `FilterValues`.\n *\n * - String values are parsed as single conditions.\n * - String arrays (repeated query params) become multiple conditions on the same field.\n *\n * @example\n * deserializeFilter({ status: \"eq.active\" })\n * // → { status: [\"==\", \"active\"] }\n *\n * deserializeFilter({ age: [\"gte.18\", \"lt.65\"] })\n * // → { age: [[\">=\", 18], [\"<\", 65]] }\n */\nexport function deserializeFilter(\n query: Record<string, any>\n): FilterValues<string> {\n const result: FilterValues<string> = {};\n\n for (const [field, raw] of Object.entries(query)) {\n if (raw === undefined) continue;\n\n // If it's already a canonical tuple [op, value], keep it as is\n if (Array.isArray(raw) && raw.length === 2 && typeof raw[0] === \"string\" && toCanonicalOp(raw[0]) === raw[0]) {\n result[field] = raw as [WhereFilterOp, unknown];\n continue;\n }\n\n if (Array.isArray(raw)) {\n if (raw.length === 0) continue;\n \n // Check if it's an array of canonical tuples\n if (Array.isArray(raw[0]) && raw[0].length === 2 && typeof raw[0][0] === \"string\" && toCanonicalOp(raw[0][0]) === raw[0][0]) {\n result[field] = raw as [WhereFilterOp, unknown][];\n continue;\n }\n\n if (raw.length === 1) {\n result[field] = typeof raw[0] === \"string\" ? deserializeSingle(raw[0]) : [\"==\", raw[0]];\n } else {\n // If the elements are strings, they might be PostgREST dot-strings (repeated params)\n if (typeof raw[0] === \"string\" && raw[0].includes(\".\")) {\n result[field] = raw.map(r => typeof r === \"string\" ? deserializeSingle(r) : ([\"==\", r] as [WhereFilterOp, unknown])) as [WhereFilterOp, unknown][];\n } else {\n // Otherwise assume it's a list of values for an implicit \"in\" or just multiple conditions\n result[field] = [\"in\", raw];\n }\n }\n } else if (typeof raw === \"string\") {\n result[field] = deserializeSingle(raw);\n } else {\n result[field] = [\"==\", raw];\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Logical conditions: serialize / deserialize\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a `LogicalCondition` or `FilterCondition` to its wire-format string.\n *\n * @example\n * serializeLogicalCondition({ column: \"status\", operator: \"==\", value: \"active\" })\n * // → \"status.eq.active\"\n *\n * serializeLogicalCondition({ type: \"or\", conditions: [...] })\n * // → \"or(status.eq.active,status.eq.pending)\"\n */\nexport function serializeLogicalCondition(\n cond: LogicalCondition | FilterCondition\n): string {\n if (\"type\" in cond) {\n // LogicalCondition (and/or)\n const inner = (cond.conditions ?? [])\n .map(serializeLogicalCondition)\n .join(\",\");\n return `${cond.type}(${inner})`;\n }\n\n // FilterCondition\n const restOp = (CANONICAL_TO_REST as any)[cond.operator] || \"eq\";\n if (Array.isArray(cond.value)) {\n const items = cond.value.map(stringifyValue).join(\",\");\n return `${cond.column}.${restOp}.(${items})`;\n }\n return `${cond.column}.${restOp}.${stringifyValue(cond.value)}`;\n}\n\n/**\n * Parse a logical condition wire-format string back into a\n * `LogicalCondition` or `FilterCondition`.\n *\n * @example\n * deserializeLogicalCondition(\"status.eq.active\")\n * // → { column: \"status\", operator: \"==\", value: \"active\" }\n *\n * deserializeLogicalCondition(\"or(status.eq.active,age.gte.18)\")\n * // → { type: \"or\", conditions: [...] }\n */\nexport function deserializeLogicalCondition(\n str: string\n): LogicalCondition | FilterCondition {\n // Check for logical group: \"and(...)\" or \"or(...)\"\n const logicalMatch = str.match(/^(and|or)\\((.+)\\)$/);\n if (logicalMatch) {\n const type = logicalMatch[1] as \"and\" | \"or\";\n const innerStr = logicalMatch[2];\n\n // Split on commas that are not inside parentheses\n const conditions: (LogicalCondition | FilterCondition)[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < innerStr.length; i++) {\n if (innerStr[i] === \"(\") depth++;\n else if (innerStr[i] === \")\") depth--;\n else if (innerStr[i] === \",\" && depth === 0) {\n conditions.push(deserializeLogicalCondition(innerStr.slice(start, i)));\n start = i + 1;\n }\n }\n conditions.push(deserializeLogicalCondition(innerStr.slice(start)));\n\n return { type, conditions };\n }\n\n // FilterCondition: \"column.op.value\"\n const firstDot = str.indexOf(\".\");\n if (firstDot === -1) {\n return { column: str, operator: \"==\", value: true };\n }\n\n const column = str.substring(0, firstDot);\n const rest = str.substring(firstDot + 1);\n\n const secondDot = rest.indexOf(\".\");\n if (secondDot === -1) {\n // \"column.value\" — treat as equality\n return { column, operator: \"==\", value: coerceValue(rest) };\n }\n\n const opStr = rest.substring(0, secondDot);\n let valueStr = rest.substring(secondDot + 1);\n const operator = toCanonicalOp(opStr) ?? \"==\";\n\n // Parse list values\n if (valueStr.startsWith(\"(\") && valueStr.endsWith(\")\")) {\n const items = valueStr.slice(1, -1).split(\",\").map(s => coerceValue(s.trim()));\n return { column, operator, value: items };\n }\n\n return { column, operator, value: coerceValue(valueStr) };\n}\n","import {\n DataDriver,\n RebaseData,\n CollectionAccessor,\n FindParams,\n FindResponse,\n Entity,\n EntityValues,\n WhereFilterOp,\n LogicalCondition,\n WhereValue\n} from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { QueryBuilder } from \"./query_builder\";\nimport { deserializeFilter } from \"./filter-dialect\";\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 // Ensure filters are in canonical [op, value] format even if passed as PostgREST strings\n const filter = params?.where ? deserializeFilter(params.where as any) : undefined;\n \n const entities = await driver.fetchCollection<M>({\n path: slug,\n limit: params?.limit,\n offset: params?.offset,\n filter,\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 const filter = params?.where ? deserializeFilter(params.where as any) : undefined;\n return driver.countEntities!({\n path: slug,\n filter\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: 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?: WhereFilterOp, 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 { RebaseData, CollectionAccessor } from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\n\n/**\n * Parameters for {@link buildRoutedRebaseData}.\n */\nexport interface RoutedRebaseDataParams {\n /**\n * The default data source. Handles every collection that does not\n * resolve to an entry in `sources` (i.e. server-transport collections,\n * which ride the Rebase client).\n */\n defaultData: RebaseData;\n\n /**\n * Per-data-source {@link RebaseData} instances for direct and custom\n * transports, keyed by data-source key (e.g. `\"analytics\"`). Server-\n * mediated sources are not listed here — they fall through to\n * `defaultData`.\n */\n sources: Record<string, RebaseData>;\n\n /**\n * Resolve the data-source key for a given collection slug or path.\n * Typically backed by the collection registry + `resolveDataSource`\n * (`resolveDataSource(registry.getCollection(path), defs).key`).\n *\n * Return `undefined` (or a key absent from `sources`) to route to the\n * default data source.\n */\n resolveKey: (slugOrPath: string) => string | undefined;\n}\n\n/**\n * Build a {@link RebaseData} that routes each collection to the right\n * backend based on its resolved data source.\n *\n * `.collection(path)` (and dynamic `data.products`-style access) resolves the\n * collection's data-source key via `resolveKey` and delegates to the matching\n * entry in `sources`, falling back to `defaultData` when there is no match.\n * Because routing keys off the *path being accessed*, a reference widget\n * inside a Firestore form that points at a Postgres collection is still\n * served by Postgres — routing follows the target, not the ancestor.\n *\n * When `sources` is empty this returns `defaultData` untouched, so the\n * single-driver setup keeps identical behaviour and identity (important for\n * effect dependencies that key off the data instance).\n *\n * @example\n * const data = buildRoutedRebaseData({\n * defaultData: client.data,\n * sources: { analytics: buildRebaseData(firestoreDriver) },\n * resolveKey: (path) => resolveDataSource(registry.getCollection(path), defs).key\n * });\n * await data.products.find(); // → default (server / Postgres)\n * await data.events.find(); // → Firestore, if `events.dataSource === \"analytics\"`\n */\nexport function buildRoutedRebaseData({\n defaultData,\n sources,\n resolveKey\n}: RoutedRebaseDataParams): RebaseData {\n\n // Fast path: nothing to route → return the default untouched (preserves\n // referential identity for effect dependencies).\n if (!sources || Object.keys(sources).length === 0) {\n return defaultData;\n }\n\n function resolve(slugOrPath: string): RebaseData {\n const key = resolveKey(slugOrPath);\n if (key && sources[key]) return sources[key];\n return defaultData;\n }\n\n function getAccessor(slugOrPath: string): CollectionAccessor {\n return resolve(slugOrPath).collection(slugOrPath);\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, mirroring\n // buildRebaseData so dynamic access routes consistently.\n return getAccessor(toSnakeCase(prop));\n }\n });\n}\n","/**\n * Table Classification\n *\n * Shared constants and pure functions for classifying database tables.\n * Used by both the server-side PostgresBackendDriver and the Studio RLS editor.\n */\n\n/** Possible categories a database table can belong to. */\nexport type TableCategory = \"rebase-internal\" | \"junction\" | \"user\";\n\n/** Schemas that are always considered Rebase-internal. */\nexport const REBASE_INTERNAL_SCHEMAS: readonly string[] = [\"rebase\", \"auth\"];\n\n/** Table-name prefixes that mark a table as Rebase-internal regardless of schema. */\nexport const REBASE_INTERNAL_PREFIXES: readonly string[] = [\n \"_rebase_\",\n \"_auth_\",\n \"drizzle_\",\n];\n\n/**\n * Synchronously classify a table based on naming conventions.\n *\n * @param tableName - The unqualified name of the table.\n * @param schemaName - The schema the table belongs to (e.g. `\"public\"`, `\"rebase\"`).\n * @returns `\"rebase-internal\"` when the table belongs to a reserved schema or\n * carries a reserved prefix; `\"user\"` otherwise.\n *\n * @remarks\n * Junction-table detection requires an async database query and is therefore\n * **not** handled by this function. Use {@link detectJunctionTables} to obtain\n * the set of junction tables, then reclassify as needed.\n */\nexport function classifyTable(\n tableName: string,\n schemaName: string,\n): TableCategory {\n if (\n REBASE_INTERNAL_SCHEMAS.includes(schemaName) ||\n REBASE_INTERNAL_PREFIXES.some((prefix) => tableName.startsWith(prefix))\n ) {\n return \"rebase-internal\";\n }\n\n return \"user\";\n}\n\n/**\n * Convenience predicate that checks whether a table is Rebase-internal.\n *\n * @param tableName - The unqualified name of the table.\n * @param schemaName - The schema the table belongs to.\n * @returns `true` if the table is classified as `\"rebase-internal\"`.\n */\nexport function isRebaseInternalTable(\n tableName: string,\n schemaName: string,\n): boolean {\n return classifyTable(tableName, schemaName) === \"rebase-internal\";\n}\n\n/** SQL query that detects junction tables in the `public` schema. */\nexport const JUNCTION_TABLES_SQL = `\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 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\n/**\n * Asynchronously detect junction (link) tables in the `public` schema.\n *\n * A junction table is defined as a table where **every** column participates in\n * at least one foreign-key constraint.\n *\n * @param executeSql - A callback that executes a raw SQL string and returns the\n * resulting rows.\n * @returns A `Set` containing the names of all detected junction tables.\n */\nexport async function detectJunctionTables(\n executeSql: (sql: string) => Promise<Record<string, unknown>[]>,\n): Promise<Set<string>> {\n const rows = await executeSql(JUNCTION_TABLES_SQL);\n const junctionTables = new Set<string>();\n\n for (const row of rows) {\n if (typeof row.table_name === \"string\") {\n junctionTables.add(row.table_name);\n }\n }\n\n return junctionTables;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.es.js","names":[],"sources":["../src/util/common.ts","../src/util/entities.ts","../src/util/collections.ts","../src/util/enums.ts","../src/util/paths.ts","../src/util/relations.ts","../src/util/resolutions.ts","../src/util/policy/sqlToPolicy.ts","../src/util/policy/securityRuleToConditions.ts","../src/util/policy/policyToPostgres.ts","../src/util/policy/evaluatePolicy.ts","../src/util/permissions.ts","../src/util/references.ts","../src/util/navigation_utils.ts","../src/util/navigation_from_path.ts","../src/util/parent_references_from_path.ts","../src/util/builders.ts","../src/util/storage.ts","../src/util/callbacks.ts","../src/util/conditions.ts","../src/util/filter-operator-resolution.ts","../src/data/resolveDataSource.ts","../src/collections/CollectionRegistry.ts","../src/collections/default-collections.ts","../src/data/query_builder.ts","../src/data/filter-dialect.ts","../src/data/buildRebaseData.ts","../src/data/buildRoutedRebaseData.ts","../src/data/sort-dialect.ts","../src/table-classification.ts"],"sourcesContent":["export const DEFAULT_ONE_OF_TYPE = \"type\"\nexport const DEFAULT_ONE_OF_VALUE = \"value\"\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 a 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 a 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 as unknown as Record<string, unknown>);\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 Record<string, unknown> | 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 {\n DefaultSelectedViewBuilder,\n DefaultSelectedViewParams,\n CollectionConfig,\n Properties,\n Property\n} from \"@rebasepro/types\";\nimport { isPropertyBuilder } from \"./entities\";\n\nexport function sortProperties<M extends Record<string, unknown>>(properties: Properties, propertiesOrder?: string[]): Properties {\n try {\n const propertiesKeys = Object.keys(properties);\n // If no propertiesOrder, just use the original keys order\n if (!propertiesOrder || propertiesOrder.length === 0) {\n return propertiesKeys\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n }\n\n // Filter propertiesOrder to only include TOP-LEVEL property keys that exist\n // (ignore nested keys like \"data.mode\" - they are for column ordering, not property filtering)\n const validOrderKeys = (propertiesOrder as string[]).filter(key => {\n // Only include top-level keys (no dots) that exist in properties\n return !key.includes(\".\") && properties[key];\n });\n\n // Track which properties we've processed\n const processedKeys = new Set<string>(validOrderKeys);\n\n // Build result starting with ordered properties\n const orderedResult = validOrderKeys\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n\n // Append any properties that were NOT in propertiesOrder (so they don't disappear!)\n const missingProperties = propertiesKeys\n .filter(key => !processedKeys.has(key))\n .map((key) => {\n const property = properties[key] as Property;\n if (!isPropertyBuilder(property) && property?.type === \"map\" && property.properties) {\n return ({\n [key]: {\n ...property,\n properties: sortProperties(property.properties, property.propertiesOrder)\n }\n });\n } else {\n return ({ [key]: property });\n }\n })\n .reduce((a: Properties, b: Properties) => ({ ...a,\n...b }), {}) as Properties;\n\n return { ...orderedResult,\n...missingProperties };\n } catch (e) {\n console.error(\"Error sorting properties\", e);\n return properties;\n }\n}\n\nexport function resolveDefaultSelectedView(\n defaultSelectedView: string | DefaultSelectedViewBuilder | undefined,\n params: DefaultSelectedViewParams\n) {\n if (!defaultSelectedView) {\n return undefined;\n } else if (typeof defaultSelectedView === \"string\") {\n return defaultSelectedView;\n } else {\n return defaultSelectedView(params);\n }\n}\n\n\nexport function getLocalChangesBackup(collection: CollectionConfig) {\n if (!collection.localChangesBackup) {\n return \"manual_apply\";\n }\n\n return collection.localChangesBackup;\n}\n\n/**\n * Returns the primary keys for a entity collection by inspecting the properties\n * and finding any properties with `isId`.\n * Fallbacks to `[\"id\"]` if no properties are marked as `isId: true`.\n * @param collection\n */\nexport function getPrimaryKeys<M extends Record<string, unknown>>(collection: CollectionConfig<M>): Extract<keyof M, string>[] {\n const properties = collection.properties;\n if (!properties) {\n return [\"id\"] as Extract<keyof M, string>[];\n }\n const ids = Object.entries(properties)\n .filter(([key, prop]) => typeof prop === \"object\" && prop !== null && \"isId\" in prop && Boolean(prop.isId))\n .map(([key]) => key);\n\n if (ids.length > 0) {\n return ids as Extract<keyof M, string>[];\n }\n return [\"id\"] as Extract<keyof M, string>[];\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","export const COLLECTION_PATH_SEPARATOR = \"::\";\n\n/**\n * Remove the entity ids from a given path\n * `products/B44RG6APH/locales` => `products::locales`\n * @param path\n */\nexport function stripCollectionPath(path: string): string {\n return segmentsToStrippedPath(fullPathToCollectionSegments(path));\n}\n\nexport function segmentsToStrippedPath(paths: string[]) {\n if (paths.length === 1)\n return paths[0];\n return paths.reduce((a, b) => `${a}${COLLECTION_PATH_SEPARATOR}${b}`);\n}\n\n/**\n * Extract the collection path routes\n * `products/B44RG6APH/locales` => [`products`, `locales`]\n * @param path\n */\nexport function fullPathToCollectionSegments(path: string): string[] {\n return path\n .split(\"/\")\n .filter((e, i) => i % 2 === 0);\n}\n","import { CollectionConfig, 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: CollectionConfig,\n resolveCollection?: (slugOrTable: string) => CollectionConfig | 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: CollectionConfig | 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 CollectionConfig;\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 CollectionConfig;\n }\n } else {\n targetCollection = evaluated;\n }\n } else if (rawTarget && typeof rawTarget === \"object\") {\n targetCollection = rawTarget as CollectionConfig;\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.engine).supportsRelations ? (targetCollection.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.engine).supportsRelations ? (targetCollection.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<CollectionConfig, Record<string, Relation>>();\n\nexport function resolveCollectionRelations(\n collection: CollectionConfig\n): Record<string, Relation> {\n const cached = _resolvedRelationsCache.get(collection);\n if (cached) return cached;\n\n if (!getDataSourceCapabilities(collection.engine).supportsRelations) return {};\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 (collection.relations) {\n collection.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 FetchService 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: CollectionConfig;\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: CollectionConfig): string {\n if (getDataSourceCapabilities(collection.engine).supportsRelations) {\n return collection.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 CollectionConfig,\n EnumValueConfig,\n EnumValues,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty,\n getDataSourceCapabilities,\n getDeclaredSubcollections\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: CollectionConfig<M>): CollectionConfig<Record<string, unknown>>[] {\n if (collection.childCollections) {\n return collection.childCollections() ?? [];\n }\n\n const declaredSubcollections = getDeclaredSubcollections(collection);\n if (getDataSourceCapabilities(collection.engine).supportsSubcollections && declaredSubcollections) {\n return declaredSubcollections() ?? [];\n }\n\n if (getDataSourceCapabilities(collection.engine).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<CollectionConfig> = { 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 CollectionConfig<Record<string, unknown>>;\n }).filter((c: CollectionConfig<Record<string, unknown>> | undefined): c is CollectionConfig<Record<string, unknown>> => Boolean(c));\n }\n\n return [];\n}\n","import { PolicyExpression, policy } from \"@rebasepro/types\";\n\n/**\n * A tiny, regex-based SQL \"parser\" for security rules.\n *\n * This is NOT a full SQL parser. It is designed to handle the subset of SQL\n * commonly used in `USING` and `WITH CHECK` clauses, enough to drive the\n * optimistic client-side UI decision.\n *\n * It handles:\n * - `field = 'literal'`\n * - `field != 'literal'`\n * - `field = current_setting('app.user_id')`\n * - `A AND B`\n * - `true`\n * - `IN (...)` (as optimistic true)\n *\n * For anything it doesn't understand, it returns a `raw` expression, which\n * the evaluator treats as \"unknown\" (and usually optimistic true).\n */\nexport function sqlToPolicy(sql: string): PolicyExpression {\n const trimmed = sql.trim();\n\n if (trimmed.toLowerCase() === \"true\") return policy.true();\n if (trimmed.toLowerCase() === \"false\") return policy.false();\n\n // Handle roles overlap (&&)\n // Matches: string_to_array(auth.roles(), ',') && ARRAY['admin', 'editor']\n const overlapMatch = trimmed.match(/^string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*&&\\s*ARRAY\\s*\\[(.+)\\]$/i);\n if (overlapMatch) {\n const roles = overlapMatch[1].split(\",\").map(s => s.trim().replace(/^'|'$/g, \"\"));\n return policy.rolesOverlap(roles);\n }\n\n // Handle roles containment (@>)\n // Matches: string_to_array(auth.roles(), ',') @> ARRAY['admin']\n const containMatch = trimmed.match(/^string_to_array\\s*\\(\\s*auth\\.roles\\(\\)\\s*,\\s*','\\s*\\)\\s*@>\\s*ARRAY\\s*\\[(.+)\\]$/i);\n if (containMatch) {\n const roles = containMatch[1].split(\",\").map(s => s.trim().replace(/^'|'$/g, \"\"));\n return policy.rolesContain(roles);\n }\n\n // Handle OR\n if (trimmed.toUpperCase().includes(\" OR \")) {\n const parts = trimmed.split(/ OR /i);\n return policy.or(...parts.map(sqlToPolicy));\n }\n\n // Handle AND (very basic split, doesn't handle nested parens properly)\n if (trimmed.toUpperCase().includes(\" AND \")) {\n const parts = trimmed.split(/ AND /i);\n return policy.and(...parts.map(sqlToPolicy));\n }\n\n // Handle = and !=\n const match = trimmed.match(/^(.+?)\\s*(!?=)\\s*(.+)$/);\n if (match) {\n const [, leftStr, op, rightStr] = match;\n const left = parseOperand(leftStr.trim());\n const right = parseOperand(rightStr.trim());\n if (left && right) {\n return policy.compare(left, op === \"=\" ? \"eq\" : \"neq\", right);\n }\n }\n\n // Fallback to raw\n return policy.raw(sql);\n}\n\nfunction parseOperand(str: string) {\n // current_setting('app.user_id') or auth.uid()\n if (/current_setting\\s*\\(\\s*'app\\.user_id'\\s*\\)/i.test(str) || /auth\\.uid\\(\\)/i.test(str)) {\n return policy.authUid();\n }\n\n // Literal string: 'value'\n const stringMatch = str.match(/^'(.+)'$/);\n if (stringMatch) {\n return policy.literal(stringMatch[1]);\n }\n\n // Bare field name\n if (/^\\w+$/.test(str)) {\n return policy.field(str);\n }\n\n return null;\n}\n","import { PolicyExpression, SecurityRule, policy } from \"@rebasepro/types\";\nimport { sqlToPolicy } from \"./sqlToPolicy\";\n\n/**\n * The normalized `USING` / `WITH CHECK` conditions for a single security rule,\n * expressed in the engine-agnostic {@link PolicyExpression} model.\n *\n * A `null` clause means \"this rule contributes no condition for that clause\";\n * consumers apply the default (Postgres denies with `false`).\n */\nexport interface RuleConditions {\n usingExpr: PolicyExpression | null;\n withCheckExpr: PolicyExpression | null;\n}\n\n/**\n * Desugars a {@link SecurityRule} — its `access`/`ownerField`/`roles` shortcuts,\n * structured `condition`/`check`, and raw `using`/`withCheck` — into a single\n * normalized {@link PolicyExpression} pair.\n *\n * **This is the linchpin against drift:** both the Postgres DDL generators and\n * the client-side evaluator consume this one function, so there is exactly one\n * definition of what a rule means. In particular, application `roles` are folded\n * into the expression here (AND'd with the base condition, matching how Postgres\n * generates the clause) rather than being handled separately by each consumer.\n */\nexport function securityRuleToConditions(rule: SecurityRule): RuleConditions {\n return {\n usingExpr: withRoles(baseUsing(rule), rule),\n withCheckExpr: withRoles(baseWithCheck(rule), rule)\n };\n}\n\nfunction baseUsing(rule: SecurityRule): PolicyExpression | null {\n if (rule.condition) return rule.condition;\n if (rule.using != null) return sqlToPolicy(rule.using);\n if (rule.access === \"public\") return policy.true();\n if (rule.ownerField) return policy.compare(policy.field(rule.ownerField), \"eq\", policy.authUid());\n return null;\n}\n\nfunction baseWithCheck(rule: SecurityRule): PolicyExpression | null {\n if (rule.check) return rule.check;\n if (rule.withCheck != null) return sqlToPolicy(rule.withCheck);\n // No explicit WITH CHECK → fall back to the USING condition, matching\n // PostgreSQL's own default behavior.\n return baseUsing(rule);\n}\n\n/**\n * AND the base condition with an application-role check, or produce a roles-only\n * condition when there is no base. Mirrors the Postgres generator so that a\n * role-scoped restrictive rule denies exactly the same set of users on both\n * sides.\n */\nfunction withRoles(base: PolicyExpression | null, rule: SecurityRule): PolicyExpression | null {\n if (!rule.roles || rule.roles.length === 0) return base;\n const rolesExpr = policy.rolesOverlap(rule.roles);\n if (rule.mode === \"restrictive\") {\n // Restrictive rule: applies ONLY if user has the roles.\n // If user DOES NOT have the roles, they are NOT restricted (passes).\n // If user HAS the roles, they must pass the base condition.\n // Logical equivalent: NOT(roles) OR base\n return base ? policy.or(policy.not(rolesExpr), base) : policy.not(rolesExpr);\n }\n return base ? policy.and(base, rolesExpr) : rolesExpr;\n}\n","import { CollectionConfig, PolicyExpression, PolicyOperand, PolicyCompareOperator, Property, ExistsInPolicyExpression } from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { getTableName } from \"../relations\";\n\n/**\n * Options for {@link policyToPostgres}.\n */\nexport interface PolicyCompileOptions {\n /**\n * Resolve a collection by slug. Required to compile\n * {@link ExistsInPolicyExpression} (`policy.existsIn`) — the compiler needs\n * the joined collection to derive its table name / schema. When omitted, the\n * join table falls back to a snake_cased slug.\n */\n resolveCollection?: (slug: string) => CollectionConfig | undefined;\n}\n\n/**\n * The lexical scope threaded through compilation. It changes when we descend\n * into an `existsIn` subquery: inside it, `field` refers to the joined table\n * (aliased) while `outerField` refers to the outer RLS row (table-qualified).\n */\ninterface CompileScope {\n /** Collection whose columns a bare `field` operand resolves against. */\n fieldCollection?: CollectionConfig;\n /** SQL prefix for `field` operands (`\"\"` at top level, `\"alias\".` in a subquery). */\n fieldPrefix: string;\n /** The outer RLS collection, for `outerField` operands. */\n outerCollection?: CollectionConfig;\n /** SQL prefix for `outerField` operands (`\"\"` at top level, `\"schema\".\"table\".` in a subquery). */\n outerPrefix: string;\n resolveCollection?: (slug: string) => CollectionConfig | undefined;\n /** Monotonic counter for generating unique subquery aliases. */\n alias: { n: number };\n}\n\n/**\n * Compiles a {@link PolicyExpression} to a PostgreSQL boolean SQL string,\n * suitable for a `USING (...)` / `WITH CHECK (...)` clause.\n *\n * This is one of the two consumers of the shared policy model (the other being\n * {@link evaluatePolicy}); the Postgres schema generators call it so that DDL\n * and the admin UI derive from the exact same expression.\n */\nexport function policyToPostgres(expr: PolicyExpression, collection?: CollectionConfig, options?: PolicyCompileOptions): string {\n return compile(expr, {\n fieldCollection: collection,\n fieldPrefix: \"\",\n outerCollection: collection,\n outerPrefix: \"\",\n resolveCollection: options?.resolveCollection,\n alias: { n: 0 }\n });\n}\n\nfunction compile(expr: PolicyExpression, scope: CompileScope): string {\n switch (expr.kind) {\n case \"true\":\n return \"true\";\n case \"false\":\n return \"false\";\n case \"and\":\n return expr.operands.length === 0\n ? \"true\"\n : expr.operands.map(o => `(${compile(o, scope)})`).join(\" AND \");\n case \"or\":\n return expr.operands.length === 0\n ? \"false\"\n : expr.operands.map(o => `(${compile(o, scope)})`).join(\" OR \");\n case \"not\":\n // Render the common `auth.uid() IS NULL` (unauthenticated) form directly.\n if (expr.operand.kind === \"authenticated\") return \"auth.uid() IS NULL\";\n return `NOT (${compile(expr.operand, scope)})`;\n case \"compare\":\n return `${operandToSql(expr.left, scope)} ${COMPARE_SQL[expr.op]} ${operandToSql(expr.right, scope)}`;\n case \"rolesOverlap\":\n return `string_to_array(auth.roles(), ',') && ${rolesArraySql(expr.roles)}`;\n case \"rolesContain\":\n return `string_to_array(auth.roles(), ',') @> ${rolesArraySql(expr.roles)}`;\n case \"authenticated\":\n return \"auth.uid() IS NOT NULL\";\n case \"existsIn\":\n return compileExistsIn(expr, scope);\n case \"raw\":\n // Full-power escape hatch: `{column}` references resolve to the bare\n // column name (matching the previous raw-SQL behavior).\n return expr.sql.replace(/\\{(\\w+)\\}/g, (_, col) => col);\n }\n}\n\n/**\n * Compiles `existsIn` to a correlated `EXISTS (SELECT 1 FROM <join> WHERE ...)`.\n * Inside the subquery, `field` operands bind to the aliased join table and\n * `outerField` operands bind to the (table-qualified) outer RLS row.\n */\nfunction compileExistsIn(expr: ExistsInPolicyExpression, scope: CompileScope): string {\n const join = scope.resolveCollection?.(expr.collection);\n const joinTable = join ? getTableName(join) : toSnakeCase(expr.collection);\n const joinSchema = schemaOf(join) ?? schemaOf(scope.outerCollection) ?? \"public\";\n const alias = `_ex${scope.alias.n++}`;\n\n // `outerField` inside the subquery must be qualified with the outer table,\n // otherwise a bare column name would bind to the joined table instead.\n const outerTable = scope.outerCollection ? getTableName(scope.outerCollection) : undefined;\n const outerSchema = schemaOf(scope.outerCollection) ?? \"public\";\n const outerPrefix = outerTable ? `\"${outerSchema}\".\"${outerTable}\".` : \"\";\n\n const innerScope: CompileScope = {\n fieldCollection: join,\n fieldPrefix: `\"${alias}\".`,\n outerCollection: scope.outerCollection,\n outerPrefix,\n resolveCollection: scope.resolveCollection,\n alias: scope.alias\n };\n return `EXISTS (SELECT 1 FROM \"${joinSchema}\".\"${joinTable}\" \"${alias}\" WHERE ${compile(expr.where, innerScope)})`;\n}\n\nconst COMPARE_SQL: Record<PolicyCompareOperator, string> = {\n eq: \"=\",\n neq: \"!=\",\n lt: \"<\",\n lte: \"<=\",\n gt: \">\",\n gte: \">=\"\n};\n\nfunction operandToSql(operand: PolicyOperand, scope: CompileScope): string {\n switch (operand.kind) {\n case \"field\":\n return `${scope.fieldPrefix}${resolveColumnName(operand.name, scope.fieldCollection)}`;\n case \"outerField\":\n return `${scope.outerPrefix}${resolveColumnName(operand.name, scope.outerCollection)}`;\n case \"literal\":\n return quoteLiteral(operand.value);\n case \"authUid\":\n return \"auth.uid()\";\n case \"authRoles\":\n return \"string_to_array(auth.roles(), ',')\";\n }\n}\n\nfunction schemaOf(collection?: CollectionConfig): string | undefined {\n return (collection as { schema?: string } | undefined)?.schema || undefined;\n}\n\nfunction resolveColumnName(propName: string, collection?: CollectionConfig): string {\n const prop = collection?.properties?.[propName] as Property | undefined;\n if (prop && \"columnName\" in prop && typeof (prop as { columnName?: unknown }).columnName === \"string\") {\n return (prop as { columnName: string }).columnName;\n }\n return toSnakeCase(propName);\n}\n\nfunction quoteLiteral(value: string | number | boolean | null): string {\n if (value === null) return \"NULL\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\") return String(value);\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\n/** Sorted, single-quoted `ARRAY['a','b']` — matches the generators' output. */\nfunction rolesArraySql(roles: readonly string[]): string {\n return `ARRAY[${[...roles].sort().map(r => `'${r}'`).join(\",\")}]`;\n}\n","import { Entity, PolicyCompareOperator, PolicyExpression, PolicyOperand } from \"@rebasepro/types\";\n\n/**\n * Result of evaluating a policy client-side. `\"unknown\"` means the expression\n * could not be decided without more information — either a raw-SQL escape-hatch\n * node (which the client deliberately never guesses) or a row-column reference\n * with no entity in hand (e.g. list-level gating). Callers decide how to resolve\n * `\"unknown\"`: fail-closed for an enforcement decision, optimistic for pure\n * visibility gating.\n */\nexport type TriState = boolean | \"unknown\";\n\n/**\n * Context for {@link evaluatePolicy}: the acting user (or none) and the row\n * being evaluated (or none, for collection-level gating).\n */\nexport interface PolicyEvalContext {\n /** The current user's id, or null/undefined when unauthenticated. */\n uid?: string | null;\n /** The current user's application roles. */\n roles?: string[];\n /** The row being evaluated, or null when no specific row is available. */\n entity: Entity | null;\n}\n\n/**\n * Evaluates a {@link PolicyExpression} against a user + row, using three-valued\n * (Kleene) logic so that `\"unknown\"` sub-results propagate soundly.\n *\n * This is the JavaScript twin of {@link policyToPostgres}: both derive from the\n * same expression, so the admin UI matches database enforcement by construction\n * for every non-raw rule.\n */\nexport function evaluatePolicy(expr: PolicyExpression, ctx: PolicyEvalContext): TriState {\n switch (expr.kind) {\n case \"true\":\n return true;\n case \"false\":\n return false;\n case \"and\":\n return kleeneAnd(expr.operands.map(o => evaluatePolicy(o, ctx)));\n case \"or\":\n return kleeneOr(expr.operands.map(o => evaluatePolicy(o, ctx)));\n case \"not\":\n return kleeneNot(evaluatePolicy(expr.operand, ctx));\n case \"compare\":\n return evaluateCompare(expr.op, expr.left, expr.right, ctx);\n case \"rolesOverlap\": {\n const userRoles = ctx.roles ?? [];\n return expr.roles.some(r => r === \"public\" || userRoles.includes(r));\n }\n case \"rolesContain\": {\n const userRoles = ctx.roles ?? [];\n return expr.roles.every(r => r === \"public\" || userRoles.includes(r));\n }\n case \"authenticated\":\n return ctx.uid != null;\n case \"existsIn\":\n // A membership subquery cannot be run client-side — server-authoritative.\n return \"unknown\";\n case \"raw\":\n // Arbitrary SQL cannot be evaluated client-side — never guess.\n return \"unknown\";\n }\n}\n\n// ── Three-valued logic ───────────────────────────────────────────────\n\nfunction kleeneAnd(values: TriState[]): TriState {\n if (values.some(v => v === false)) return false;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return true;\n}\n\nfunction kleeneOr(values: TriState[]): TriState {\n if (values.some(v => v === true)) return true;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return false;\n}\n\nfunction kleeneNot(value: TriState): TriState {\n if (value === \"unknown\") return \"unknown\";\n return !value;\n}\n\n// ── Comparison ───────────────────────────────────────────────────────\n\ntype ResolvedOperand = { known: false } | { known: true; value: unknown };\n\nfunction resolveOperand(operand: PolicyOperand, ctx: PolicyEvalContext): ResolvedOperand {\n switch (operand.kind) {\n case \"literal\":\n return { known: true, value: operand.value };\n case \"authUid\":\n return { known: true, value: ctx.uid ?? null };\n case \"authRoles\":\n return { known: true, value: ctx.roles ?? [] };\n case \"field\":\n // Can't resolve a row column without the row.\n if (!ctx.entity) return { known: false };\n return { known: true, value: ctx.entity.values[operand.name] };\n case \"outerField\":\n // Only meaningful inside an `existsIn` subquery (server-authoritative).\n return { known: false };\n }\n}\n\nfunction evaluateCompare(\n op: PolicyCompareOperator,\n left: PolicyOperand,\n right: PolicyOperand,\n ctx: PolicyEvalContext\n): TriState {\n const l = resolveOperand(left, ctx);\n const r = resolveOperand(right, ctx);\n if (!l.known || !r.known) return \"unknown\";\n\n const a = l.value;\n const b = r.value;\n\n if (a === null || b === null) {\n if (op === \"eq\") return false;\n if (op === \"neq\") return true;\n return \"unknown\";\n }\n\n if (op === \"eq\") return a === b;\n if (op === \"neq\") return a !== b;\n\n if (typeof a === \"string\" && typeof b === \"string\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n if (typeof a === \"number\" && typeof b === \"number\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n if (typeof a === \"bigint\" && typeof b === \"bigint\") {\n if (op === \"lt\") return a < b;\n if (op === \"lte\") return a <= b;\n if (op === \"gt\") return a > b;\n if (op === \"gte\") return a >= b;\n }\n\n return \"unknown\";\n}\n","import { Entity, CollectionConfig, getDataSourceCapabilities, SecurityOperation, SecurityRule, User } from \"@rebasepro/types\";\nimport { securityRuleToConditions } from \"./policy/securityRuleToConditions\";\nimport { evaluatePolicy, PolicyEvalContext, TriState } from \"./policy/evaluatePolicy\";\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\n/**\n * How to resolve a policy result that cannot be decided client-side (a raw-SQL\n * escape-hatch rule, or a row-column reference with no row in hand).\n *\n * - `\"allow\"` (default): optimistic — used for admin-UI gating, where Postgres\n * remains the authoritative gate and hiding a working action is worse than\n * showing one the server may reject.\n * - `\"deny\"`: fail-closed — used by real enforcement callers (e.g. a driver\n * applying policies in-process), so an undecidable rule never silently allows.\n */\nexport type UnknownResolution = \"allow\" | \"deny\";\n\nexport interface CheckOperationOptions {\n onUnknown?: UnknownResolution;\n}\n\n/** Combine clause results with AND under three-valued (Kleene) logic. */\nfunction kleeneAnd(values: TriState[]): TriState {\n if (values.some(v => v === false)) return false;\n if (values.some(v => v === \"unknown\")) return \"unknown\";\n return true;\n}\n\n/** The operations a rule covers, mirroring the Postgres generator's resolution. */\nfunction ruleOperations(rule: SecurityRule): readonly SecurityOperation[] {\n return rule.operations && rule.operations.length > 0\n ? rule.operations\n : [rule.operation ?? \"all\"];\n}\n\nfunction ruleApplies(rule: SecurityRule, targetOperation: SecurityOperation): boolean {\n const ops = ruleOperations(rule);\n return ops.includes(targetOperation) || ops.includes(\"all\");\n}\n\n/**\n * Evaluate a single rule for one operation, returning a tri-state.\n *\n * A `null` clause (the rule contributes no condition for a required clause)\n * denies — matching Postgres, which emits `USING (false)` / `WITH CHECK (false)`\n * in that case. USING applies to SELECT/UPDATE/DELETE; WITH CHECK to\n * INSERT/UPDATE; both must pass for UPDATE.\n */\nfunction evaluateRuleForOperation(rule: SecurityRule, ctx: PolicyEvalContext, targetOperation: SecurityOperation): TriState {\n const { usingExpr, withCheckExpr } = securityRuleToConditions(rule);\n const clause = (expr: typeof usingExpr): TriState => expr === null ? false : evaluatePolicy(expr, ctx);\n\n const needsUsing = targetOperation !== \"insert\";\n const needsWithCheck = targetOperation === \"insert\" || targetOperation === \"update\";\n\n const results: TriState[] = [];\n if (needsUsing) results.push(clause(usingExpr));\n if (needsWithCheck) results.push(clause(withCheckExpr));\n return kleeneAnd(results);\n}\n\nfunction resolveTriState(value: TriState, onUnknown: UnknownResolution): boolean {\n if (value === \"unknown\") return onUnknown === \"allow\";\n return value;\n}\n\n/**\n * Decide whether an operation is permitted for a user on a (possibly null) row,\n * by evaluating the collection's security rules with the shared policy model —\n * the same model compiled to Postgres RLS DDL, so the decision matches database\n * enforcement for every non-raw rule.\n *\n * @param options.onUnknown how to treat rules that cannot be decided\n * client-side (raw SQL, or row predicates with no row). Defaults to `\"allow\"`\n * for optimistic UI gating; enforcement callers should pass `\"deny\"`.\n */\nexport function checkOperation<M extends Record<string, unknown>, USER extends User>(\n collection: CollectionConfig<M>,\n authContext: AuthContext<USER>,\n entity: Entity<M> | null,\n targetOperation: SecurityOperation,\n options?: CheckOperationOptions\n): boolean {\n const onUnknown = options?.onUnknown ?? \"allow\";\n const securityRules = getDataSourceCapabilities(collection.engine).supportsRLS ? collection.securityRules : undefined;\n if (!securityRules || securityRules.length === 0) {\n return true;\n }\n\n const applicableRules = securityRules.filter((r: SecurityRule) => ruleApplies(r, targetOperation));\n if (applicableRules.length === 0) return false;\n\n const ctx: PolicyEvalContext = {\n uid: authContext.user?.uid,\n roles: authContext.user?.roles ?? [],\n entity\n };\n\n let grantedByPermissive = false;\n let deniedByRestrictive = false;\n let hasPermissive = false;\n\n for (const rule of applicableRules) {\n const mode = rule.mode || \"permissive\";\n const passed = resolveTriState(evaluateRuleForOperation(rule, ctx, targetOperation), onUnknown);\n\n if (mode === \"restrictive\") {\n if (!passed) {\n deniedByRestrictive = true;\n break;\n }\n } else {\n hasPermissive = true;\n if (passed) grantedByPermissive = true;\n }\n }\n\n if (deniedByRestrictive) return false;\n return hasPermissive ? grantedByPermissive : false;\n}\n\nexport function canReadCollection<M extends Record<string, unknown>, USER extends User>\n (\n collection: CollectionConfig<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: CollectionConfig<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: CollectionConfig<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: CollectionConfig<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 { CollectionConfig } from \"@rebasepro/types\";\n\nexport function getEntityImagePreviewPropertyKey<M extends Record<string, unknown>>(collection: CollectionConfig<M>): string | undefined {\n\n // find first storage property of type image\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // alternatively, look for the first array of images\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage?.acceptedFiles?.includes(\"image/*\")) {\n return key;\n }\n }\n // also check for URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.ui?.url === \"image\") {\n return key;\n }\n }\n // and arrays of URL properties with image preview type\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && property.of && !Array.isArray(property.of) && property.of.type === \"string\" && property.of.ui?.url === \"image\") {\n return key;\n }\n }\n // fallback: any storage property without explicit acceptedFiles (e.g. a generic \"picture\" field)\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"string\" && property.storage && !property.storage.acceptedFiles) {\n return key;\n }\n }\n // fallback: any array of storage properties without explicit acceptedFiles\n for (const key in collection.properties) {\n const property = collection.properties[key];\n if (property.type === \"array\" && !Array.isArray(property.of) && property.of?.type === \"string\" && property.of.storage && !property.of.storage.acceptedFiles) {\n return key;\n }\n }\n return undefined;\n}\n","import { CollectionConfig } from \"@rebasepro/types\";\n\nimport { getSubcollections } from \"./resolutions\";\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n\nexport function addInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s;\n else return `/${s}`;\n}\n\nexport function getLastSegment(path: string) {\n const cleanPath = removeInitialAndTrailingSlashes(path);\n if (cleanPath.includes(\"/\")) {\n const segments = cleanPath.split(\"/\");\n return segments[segments.length - 1];\n }\n return cleanPath;\n}\n\nexport function resolveCollectionPathIds(path: string, allCollections: CollectionConfig[]): string {\n let remainingPath = removeInitialAndTrailingSlashes(path);\n if (!remainingPath) {\n return \"\";\n }\n\n let currentCollections: CollectionConfig[] | undefined = allCollections;\n const resolvedPathParts: string[] = [];\n\n while (remainingPath.length > 0) {\n if (!currentCollections || currentCollections.length === 0) {\n // We have remaining path segments but no more collections to match against\n console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath);\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n let foundMatch = false;\n // Sort potential matches by length descending to prioritize longer matches (e.g., \"a/b\" over \"a\")\n const potentialMatches: { col: CollectionConfig; match: string; }[] = currentCollections\n .flatMap(col => [{\n col,\n match: col.slug\n }])\n .filter(p => p.match && remainingPath.startsWith(p.match))\n .sort((a, b) => b.match.length - a.match.length);\n\n if (potentialMatches.length > 0) {\n const {\n col: foundCollection,\n match: matchString\n } = potentialMatches[0];\n\n resolvedPathParts.push(foundCollection.slug); // Use the defined path\n remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));\n\n // Check if we are at the end of the path\n if (remainingPath.length === 0) {\n foundMatch = true;\n break; // Path ends with a collection segment\n }\n\n // The next segment must be a entity ID\n const idSeparatorIndex = remainingPath.indexOf(\"/\");\n let entityId: string | number;\n if (idSeparatorIndex > -1) {\n entityId = remainingPath.substring(0, idSeparatorIndex);\n remainingPath = remainingPath.substring(idSeparatorIndex + 1);\n } else {\n // This should not happen if the original path is valid (odd segments)\n // but handle it defensively: assume the rest is the ID\n entityId = remainingPath;\n remainingPath = \"\";\n console.warn(`resolveCollectionPathIds: Path seems to end with a entity ID \"${entityId}\" instead of a collection segment in original path \"${path}\". This might indicate an invalid input path.`);\n // Even if it ends here, we still need to push the ID\n }\n\n resolvedPathParts.push(entityId); // Append entity ID\n currentCollections = getSubcollections(foundCollection); // Move to subcollections\n foundMatch = true;\n\n if (!currentCollections && remainingPath.length > 0) {\n // Warn if the path continues but no subcollections were defined\n console.warn(`resolveCollectionPathIds: Path continues after entity ID \"${entityId}\", but no subcollections are defined for the preceding collection \"${foundCollection.slug}\" in path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n\n }\n\n if (!foundMatch) {\n // Collection definition not found for the start of the remaining path\n console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with \"${remainingPath}\" in original path \"${path}\". Appending remaining original path.`);\n resolvedPathParts.push(remainingPath); // Append the rest\n remainingPath = \"\"; // Stop processing\n break;\n }\n }\n\n return resolvedPathParts.join(\"/\");\n}\n\n/**\n * Find the corresponding view at any depth for a given path.\n * Note that path or segments of the paths can be collection aliases.\n * @param slugOrPath\n * @param collections\n */\nexport function getCollectionBySlugWithin(slugOrPath: string, collections: CollectionConfig[]): CollectionConfig | undefined {\n\n const subpaths = removeInitialAndTrailingSlashes(slugOrPath).split(\"/\");\n if (subpaths.length % 2 === 0) {\n throw Error(`getCollectionBySlug: Collection paths must have an odd number of segments: ${slugOrPath}`);\n }\n\n const subpathCombinations = getCollectionPathsCombinations(subpaths);\n let result: CollectionConfig | undefined;\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n const navigationEntry = collections && collections\n .sort((a, b) => (a.slug ?? \"\").localeCompare(b.slug ?? \"\"))\n .find((entry) => entry.slug === subpathCombination);\n\n if (navigationEntry) {\n\n if (subpathCombination === slugOrPath) {\n result = navigationEntry;\n } else if (getSubcollections(navigationEntry).length > 0) {\n const newPath = slugOrPath.replace(subpathCombination, \"\").split(\"/\").slice(2).join(\"/\");\n if (newPath.length > 0)\n result = getCollectionBySlugWithin(newPath, getSubcollections(navigationEntry));\n }\n }\n if (result) break;\n }\n return result;\n}\n\n/**\n * Get the subcollection combinations from a path:\n * \"sites/es/locales\" => [\"sites/es/locales\", \"sites\"]\n * @param subpaths\n */\nexport function getCollectionPathsCombinations(subpaths: string[]): string[] {\n const entries = subpaths.length > 0 && subpaths.length % 2 === 0 ? subpaths.splice(0, subpaths.length - 1) : subpaths;\n\n const length = entries.length;\n const result: string[] = [];\n for (let i = length; i > 0; i = i - 2) {\n result.push(entries.slice(0, i).join(\"/\"));\n }\n return result;\n}\n","import { CollectionConfig } from \"@rebasepro/types\";\ntype EntityCustomView<M extends Record<string, unknown> = Record<string, unknown>> = { key: string; [key: string]: unknown };\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"./resolutions\";\n\nexport type NavigationViewInternal<M extends Record<string, unknown> = Record<string, unknown>> =\n | NavigationViewEntityInternal<M>\n | NavigationViewCollectionInternal<M>\n | NavigationViewEntityCustomInternal<M>;\n\nexport interface NavigationViewEntityInternal<M extends Record<string, unknown>> {\n type: \"entity\";\n entityId: string | number;\n slug: string;\n path: string;\n parentCollection: CollectionConfig<M>;\n}\n\nexport interface NavigationViewCollectionInternal<M extends Record<string, unknown>> {\n type: \"collection\";\n id: string;\n slug: string;\n path: string;\n collection: CollectionConfig<M>;\n}\n\nexport interface NavigationViewEntityCustomInternal<M extends Record<string, unknown>> {\n type: \"custom_view\";\n slug: string;\n path: string;\n entityId: string | number;\n view: EntityCustomView<M>;\n}\n\nexport function getNavigationEntriesFromPath(props: {\n path: string,\n collections: CollectionConfig[] | undefined,\n currentFullPath?: string,\n contextEntityViews?: EntityCustomView[]\n}): NavigationViewInternal[] {\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: NavigationViewInternal[] = [];\n for (let i = 0; i < subpathCombinations.length; i++) {\n const subpathCombination = subpathCombinations[i];\n\n const collection = collections && collections.find((entry) => entry.slug === subpathCombination);\n\n if (collection) {\n const collectionPath = currentFullPath && currentFullPath.length > 0\n ? (currentFullPath + \"/\" + collection.slug)\n : collection.slug;\n result.push({\n type: \"collection\",\n id: collection.slug,\n slug: collectionPath,\n path: collectionPath,\n collection\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({\n type: \"entity\",\n entityId,\n slug: collectionPath,\n path,\n parentCollection: collection\n });\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 const entityViews = collection.entityViews;\n const customView = entityViews && entityViews\n .map((entry) => resolveEntityView(entry, props.contextEntityViews))\n .filter((v): v is EntityCustomView => v != null)\n .find((entry) => entry.key === newPath);\n const subcollections = getSubcollections(collection);\n if (customView) {\n result.push({\n type: \"custom_view\",\n slug: collectionPath,\n entityId: entityId,\n path: path + \"/\" + customView.key,\n view: customView\n });\n } else if (subcollections) {\n result.push(...getNavigationEntriesFromPath({\n path: newPath,\n collections: subcollections,\n currentFullPath: path,\n contextEntityViews: props.contextEntityViews\n }));\n }\n }\n }\n break;\n }\n\n }\n return result;\n}\n\nfunction resolveEntityView(entityView: string | EntityCustomView, contextEntityViews?: EntityCustomView[]): EntityCustomView | undefined {\n if (typeof entityView === \"string\") {\n return contextEntityViews?.find((entry) => entry.key === entityView);\n } else {\n return entityView;\n }\n}\n","import { CollectionConfig, EntityReference } from \"@rebasepro/types\";\nimport { getCollectionPathsCombinations, removeInitialAndTrailingSlashes } from \"./navigation_utils\";\nimport { getSubcollections } from \"./resolutions\";\n\nexport function getParentReferencesFromPath(props: {\n path: string,\n collections: CollectionConfig[] | 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: CollectionConfig | 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 {\n ArrayProperty,\n BooleanProperty,\n DateProperty,\n CollectionConfig,\n FirebaseCollectionConfig,\n FirebaseProperties,\n GeopointProperty,\n InferEntityType,\n MapProperty,\n MongoDBCollectionConfig,\n MongoProperties,\n NumberProperty,\n PostgresCollectionConfig,\n PostgresProperties,\n Property,\n ReferenceProperty,\n StringProperty,\n User\n} from \"@rebasepro/types\";\n\n\n/**\n * @deprecated Use {@link defineCollection} instead — it infers property\n * types automatically (autocomplete on `titleProperty`, `sort`,\n * `propertiesOrder`, callbacks) without manual generics.\n * `buildCollection` is kept for FireCMS migration compatibility and will\n * be removed before 1.0.\n *\n * @group Builder\n */\nexport function buildCollection<\n M extends Record<string, unknown> = Record<string, unknown>,\n USER extends User = User>\n (\n collection: CollectionConfig<M, USER>\n ): CollectionConfig<M, USER> {\n return collection;\n}\n\n// ── defineCollection ─────────────────────────────────────────────────────\n// A smarter builder that uses `const` type-parameter inference (TS 5.0+)\n// to capture literal property types automatically. This gives you\n// autocomplete on `titleProperty`, `sort`, `propertiesOrder`, `fixedFilter`,\n// callbacks, etc. — without writing `as const` or passing manual generics.\n\n/**\n * Define a PostgreSQL-backed collection with full type inference.\n *\n * The `const P` generic captures literal property types from your\n * `properties` object, which enables autocomplete on `titleProperty`,\n * `sort`, `propertiesOrder`, `fixedFilter`, and entity callbacks.\n *\n * @example\n * ```ts\n * const products = defineCollection({\n * name: \"Products\",\n * slug: \"products\",\n * table: \"products\",\n * properties: {\n * name: { name: \"Name\", type: \"string\", validation: { required: true } },\n * price: { name: \"Price\", type: \"number\" },\n * },\n * titleProperty: \"name\", // ✅ autocomplete: \"name\" | \"price\"\n * sort: [\"price\", \"asc\"], // ✅ autocomplete on first element\n * });\n * ```\n *\n * @group Builder\n */\nexport function defineCollection<\n const P extends PostgresProperties,\n USER extends User = User\n>(\n collection: Omit<PostgresCollectionConfig<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): PostgresCollectionConfig<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Define a Firestore-backed collection with full type inference.\n * @group Builder\n */\nexport function defineCollection<\n const P extends FirebaseProperties,\n USER extends User = User\n>(\n collection: Omit<FirebaseCollectionConfig<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): FirebaseCollectionConfig<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Define a MongoDB-backed collection with full type inference.\n * @group Builder\n */\nexport function defineCollection<\n const P extends MongoProperties,\n USER extends User = User\n>(\n collection: Omit<MongoDBCollectionConfig<InferEntityType<P>, USER>, \"properties\"> & { properties: P }\n): MongoDBCollectionConfig<InferEntityType<P>, USER> & { properties: P };\n\n/**\n * Implementation — delegates to the correct overload at the type level.\n * At runtime this is a plain identity function.\n */\nexport function defineCollection(\n collection: CollectionConfig\n): CollectionConfig {\n return collection;\n}\n\n/**\n * @deprecated Use plain typed property objects with {@link defineCollection}\n * instead — `defineCollection` infers property types automatically, making\n * this wrapper unnecessary. `buildProperty` is kept for FireCMS migration\n * compatibility and will be removed before 1.0.\n *\n * @group Builder\n */\nexport function buildProperty<T, P extends Property = Property>(\n property: P\n):\n P extends StringProperty ? StringProperty :\n P extends NumberProperty ? NumberProperty :\n P extends BooleanProperty ? BooleanProperty :\n P extends DateProperty ? DateProperty :\n P extends GeopointProperty ? GeopointProperty :\n P extends ReferenceProperty ? ReferenceProperty :\n P extends ArrayProperty ? ArrayProperty :\n P extends MapProperty ? MapProperty : never {\n\n // SAFETY: Identity function — P is a subtype of the conditional return type by definition\n return property as unknown as ReturnType<typeof buildProperty<T, P>>;\n}\n","import { ArrayProperty, EntityValues, StorageConfig, StorageSource, StorageSourceRegistry, StringProperty, UploadedFileContext } from \"@rebasepro/types\";\nimport { randomString } from \"@rebasepro/utils\";\n\n/**\n * Resolve the {@link StorageSource} to use for a property, given the key\n * referenced by `StorageConfig.storageSource`.\n *\n * Resolution priority:\n * 1. No `sourceKey` → the default source (backward compatible).\n * 2. An explicit {@link StorageSourceRegistry} (e.g. `client.storageRegistry`).\n * 3. A `sources` lookup map (e.g. the `StorageSourcesContext`).\n * 4. Fall back to the default source.\n *\n * Shared by the upload hook, the markdown editor, and the read-only previews\n * so the resolution logic lives in one place.\n *\n * @group Storage\n */\nexport function resolveStorageSource(params: {\n /** Key from `StorageConfig.storageSource`. */\n sourceKey?: string | null;\n /** Built sources keyed by storage-source key (e.g. from context). */\n sources?: Record<string, StorageSource>;\n /** Optional explicit registry — takes precedence over `sources`. */\n registry?: StorageSourceRegistry;\n /** Default source, used when no key is set or the key cannot be resolved. */\n defaultSource: StorageSource;\n}): StorageSource {\n const { sourceKey, sources, registry, defaultSource } = params;\n if (!sourceKey) return defaultSource;\n if (registry) return registry.getOrDefault(sourceKey);\n const fromSources = sources?.[sourceKey];\n if (fromSources) return fromSources;\n return defaultSource;\n}\n\ninterface ResolveFilenameStringParams<M extends Record<string, unknown>> {\n input: string | ((context: UploadedFileContext) => (Promise<string> | string));\n storage: StorageConfig;\n values: EntityValues<M>;\n entityId?: string | number;\n path?: string;\n property: StringProperty | ArrayProperty,\n file: File;\n propertyKey: string;\n}\n\nexport async function resolveStorageFilenameString<M extends Record<string, unknown>>(\n {\n input,\n storage,\n values,\n entityId,\n path,\n property,\n file,\n propertyKey\n }: ResolveFilenameStringParams<M>): Promise<string> {\n let result;\n\n if (typeof input === \"function\") {\n result = await input({\n path,\n entityId,\n values,\n property,\n file,\n storage,\n propertyKey\n });\n if (!result)\n console.warn(\"Storage callback returned empty result. Using default name value\")\n } else {\n result = replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n });\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n\ninterface ResolveStoragePathStringParams<M extends Record<string, unknown>> {\n input: string | ((context: UploadedFileContext) => string);\n storage: StorageConfig;\n values: EntityValues<M>;\n entityId?: string | number;\n path?: string;\n property: StringProperty | ArrayProperty;\n file: File;\n propertyKey: string;\n}\n\nexport function resolveStoragePathString<M extends Record<string, unknown>>(\n {\n input,\n storage,\n values,\n entityId,\n path,\n property,\n file,\n propertyKey\n }: ResolveStoragePathStringParams<M>): string {\n let result;\n if (typeof input === \"function\") {\n result = input({\n path,\n entityId,\n values,\n property,\n file,\n storage,\n propertyKey\n });\n if (!result)\n console.warn(\"Storage callback returned empty result. Using default name value\")\n } else {\n result = replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n });\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n\ninterface Placeholders {\n file: File;\n input: string;\n entityId?: string | number;\n propertyKey: string;\n path?: string;\n}\n\nfunction replacePlaceholders({\n file,\n input,\n entityId,\n propertyKey,\n path\n}: Placeholders) {\n const ext = file.name.split(\".\").pop();\n let result = input\n .replace(\"{propertyKey}\", propertyKey)\n .replace(\"{rand}\", randomString())\n .replace(\"{file}\", file.name)\n .replace(\"{file.type}\", file.type);\n if (entityId) {\n result = result.replace(\"{entityId}\", String(entityId));\n }\n if (path) {\n result = result.replace(\"{path}\", path);\n }\n if (ext) {\n result = result.replace(\"{file.ext}\", ext);\n const name = file.name.replace(`.${ext}`, \"\");\n result = result.replace(\"{file.name}\", name)\n }\n\n if (!result)\n result = randomString() + \"_\" + file.name;\n\n return result;\n}\n","import { CollectionCallbacks, Properties, RebaseCallContext } from \"@rebasepro/types\";\n\n/**\n * Context passed to entity lifecycle callbacks.\n * @group Models\n */\nexport type EntityCallbackContext = RebaseCallContext;\n\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 CollectionCallbacks object recursively.\n */\nexport const buildPropertyCallbacks = (properties: Properties): CollectionCallbacks | undefined => {\n if (!properties) return undefined;\n\n const propertyCallbacks: CollectionCallbacks = {};\n\n if (hasPropertyCallbacks(properties, \"afterRead\")) {\n propertyCallbacks.afterRead = async (props) => {\n const row = props.row;\n const processedValues = await processProperties(\n properties,\n row,\n row,\n props as unknown,\n \"afterRead\"\n );\n return { ...props.row, ...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","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","import {\n ALL_WHERE_FILTER_OPS,\n DataType,\n getDataSourceCapabilities,\n Property,\n WhereFilterOp\n} from \"@rebasepro/types\";\n\n/**\n * Default operators offered per property type, before engine capabilities and\n * per-property narrowing are applied. These mirror what the built-in filter\n * fields can render.\n */\nconst COMPARISON_OPS: readonly WhereFilterOp[] = [\"==\", \"!=\", \">\", \">=\", \"<\", \"<=\"];\nconst NULL_CHECK_OPS: readonly WhereFilterOp[] = [\"is-null\", \"is-not-null\"];\nconst MEMBERSHIP_OPS: readonly WhereFilterOp[] = [\"in\", \"not-in\"];\nconst PATTERN_OPS: readonly WhereFilterOp[] = [\"like\", \"ilike\", \"not-like\", \"not-ilike\"];\n\nconst DEFAULT_OPS_BY_TYPE: Partial<Record<DataType, readonly WhereFilterOp[]>> = {\n string: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...PATTERN_OPS, ...NULL_CHECK_OPS],\n number: [...COMPARISON_OPS, ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n date: [...COMPARISON_OPS, ...NULL_CHECK_OPS],\n boolean: [\"==\", \"!=\", ...NULL_CHECK_OPS],\n reference: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS],\n relation: [\"==\", \"!=\", ...MEMBERSHIP_OPS, ...NULL_CHECK_OPS]\n // geopoint, map, vector, binary, array (as a container): not filterable\n // through the generic filter UI.\n};\n\n/** Operators offered when the property is an *array of* a filterable type. */\nconst ARRAY_OPS: readonly WhereFilterOp[] = [\"array-contains\", \"array-contains-any\"];\n\nexport interface ResolveFilterOperatorsParams {\n /**\n * The property to filter on. For array properties, pass the **item**\n * property (`property.of`) together with `isArray: true` — the same\n * convention the filter field dispatchers use.\n */\n property: Property;\n /** True when filtering an array of `property`. */\n isArray?: boolean;\n /**\n * The engine backing the collection (`collection.engine`, e.g.\n * `\"postgres\"`, `\"firestore\"`). Falls back to the default engine's\n * capabilities when omitted.\n */\n engine?: string;\n}\n\n/**\n * Resolve which filter operators the UI should offer for a property.\n *\n * The result is the **intersection** of three sets:\n * 1. what the engine can execute — {@link DataSourceCapabilities.filterOperators}\n * (e.g. Firestore cannot run the LIKE family);\n * 2. what makes sense for the property type (e.g. no `>` on booleans);\n * 3. the developer's optional narrowing — `property.ui.filterOperators`.\n *\n * Returns an empty array when the property is not filterable (either by\n * type, or because the developer disabled it with `filterOperators: []`).\n *\n * @group Models\n */\nexport function resolveFilterOperators({\n property,\n isArray,\n engine\n}: ResolveFilterOperatorsParams): WhereFilterOp[] {\n const typeDefaults: readonly WhereFilterOp[] = isArray\n ? ARRAY_OPS\n : DEFAULT_OPS_BY_TYPE[property.type] ?? [];\n if (typeDefaults.length === 0) return [];\n\n const engineOps = new Set(getDataSourceCapabilities(engine).filterOperators ?? ALL_WHERE_FILTER_OPS);\n\n const narrowing = property.ui?.filterOperators;\n const narrowingSet = narrowing !== undefined ? new Set(narrowing) : undefined;\n\n return typeDefaults.filter(op =>\n engineOps.has(op) && (narrowingSet === undefined || narrowingSet.has(op)));\n}\n","import {\n DataSourceDefinition,\n ResolvedDataSource,\n DEFAULT_DATA_SOURCE_KEY,\n getDataSourceCapabilities\n} from \"@rebasepro/types\";\n\n/**\n * The subset of a collection needed to resolve its data source. Accepting a\n * structural type (rather than the full `CollectionConfig`) keeps this usable\n * from anywhere — frontend router, backend registry, editor — without coupling\n * to the collection union.\n */\nexport interface DataSourceResolvable {\n /** Preferred routing key. */\n dataSource?: string;\n /** Engine type discriminant (set on variant collection types). */\n engine?: string;\n /** Within-engine instance. */\n databaseId?: string;\n}\n\n/** A lookup of data-source definitions by key. */\nexport type DataSourceRegistry = Record<string, DataSourceDefinition>;\n\n/**\n * Build a keyed registry from a list of {@link DataSourceDefinition}s.\n * Later entries win on key collision.\n */\nexport function createDataSourceRegistry(definitions?: DataSourceDefinition[]): DataSourceRegistry {\n const registry: DataSourceRegistry = {};\n for (const def of definitions ?? []) {\n registry[def.key] = def;\n }\n return registry;\n}\n\n/**\n * Resolve the effective data source for a collection — the single source of\n * truth shared by the frontend router, the backend driver registry, and the\n * editor's capability lookups.\n *\n * Resolution order:\n * 1. The routing **key** is `collection.dataSource`, else\n * {@link DEFAULT_DATA_SOURCE_KEY}.\n * 2. If a definition is registered for that key, it provides `engine`,\n * `transport`, and `databaseId`.\n * 3. Otherwise values are synthesized: `engine` from `collection.engine`\n * (or the key, or `\"postgres\"`), `transport` defaults to `\"server\"`,\n * and `databaseId` from the collection.\n *\n * `capabilities` are always derived from the resolved `engine`, so two\n * data sources sharing an engine share capabilities.\n *\n * @param collection the collection (or any object carrying the routing fields)\n * @param registry optional registry of declared data sources\n */\nexport function resolveDataSource(\n collection: DataSourceResolvable | undefined,\n registry?: DataSourceRegistry\n): ResolvedDataSource {\n const key = collection?.dataSource ?? DEFAULT_DATA_SOURCE_KEY;\n const def = registry?.[key];\n\n const engine = def?.engine\n ?? collection?.engine\n ?? (key !== DEFAULT_DATA_SOURCE_KEY ? key : \"postgres\");\n\n const transport = def?.transport ?? \"server\";\n const databaseId = collection?.databaseId ?? def?.databaseId;\n\n return {\n key,\n engine,\n transport,\n databaseId,\n capabilities: getDataSourceCapabilities(engine)\n };\n}\n","import {\n ArrayProperty,\n CollectionCallbacks,\n EngineProperties,\n CollectionConfig,\n getDataSourceCapabilities,\n getDeclaredSubcollections,\n NumberProperty,\n Properties,\n Property,\n Relation,\n RelationProperty,\n StringProperty\n} from \"@rebasepro/types\";\nimport { deepEqual } from \"fast-equals\";\n\nimport {\n enumToObjectEntries,\n findRelation,\n getSubcollections,\n getTableName,\n resolveCollectionRelations,\n sanitizeRelation\n} from \"../util\";\nimport { deepClone, mergeDeep, removeFunctions } from \"@rebasepro/utils\";\nimport { DataSourceRegistry, resolveDataSource } from \"../data/resolveDataSource\";\n\nexport class CollectionRegistry {\n\n /**\n * Declared data sources, used during normalization to resolve each\n * collection's engine (so `dataSource`-only collections get the right\n * capabilities). Empty by default.\n */\n private dataSources: DataSourceRegistry = {};\n\n /**\n * Global lifecycle callbacks applied to every collection.\n * Runs on all data paths (REST, WebSocket, `rebase.data`).\n * Execution order: global → collection → property callbacks.\n */\n private _globalCallbacks?: CollectionCallbacks;\n\n /**\n * Set global lifecycle callbacks that apply to every collection.\n * Typically called once during backend initialization.\n */\n setGlobalCallbacks(callbacks: CollectionCallbacks): void {\n this._globalCallbacks = callbacks;\n }\n\n /**\n * Get the currently registered global callbacks, if any.\n */\n getGlobalCallbacks(): CollectionCallbacks | undefined {\n return this._globalCallbacks;\n }\n\n // Normalized runtime layer (used by Data Grid / UI)\n private collectionsByTableName = new Map<string, CollectionConfig>();\n private collectionsBySlug = new Map<string, CollectionConfig>();\n private rootCollections: CollectionConfig[] = [];\n private cachedCollectionsList: CollectionConfig[] | null = null;\n\n // Raw configuration layer (used by Collection Editor AST generator)\n private rawCollectionsByTableName = new Map<string, CollectionConfig>();\n private rawCollectionsBySlug = new Map<string, CollectionConfig>();\n private rawRootCollections: CollectionConfig[] = [];\n private cachedRawCollectionsList: CollectionConfig[] | null = null;\n\n // Entity 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 lastRawInputEntity: ReturnType<typeof removeFunctions>[] | null = null;\n\n constructor(collections?: CollectionConfig[], dataSources?: DataSourceRegistry) {\n if (dataSources) this.dataSources = dataSources;\n if (collections) {\n this.registerMultiple(collections);\n }\n }\n\n /**\n * Provide the declared data sources used to resolve each collection's\n * engine during normalization. Set this before registering collections.\n * Returns true if the registry changed (callers may re-register).\n */\n setDataSources(dataSources: DataSourceRegistry): boolean {\n if (deepEqual(this.dataSources, dataSources)) return false;\n this.dataSources = dataSources ?? {};\n return true;\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 * entity. Only re-normalizes and re-registers when the raw input actually changed.\n * @param collections\n */\n registerMultiple(collections: CollectionConfig[]): 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 rawEntity = collections.map(c => removeFunctions(c));\n if (this.lastRawInputEntity && deepEqual(this.lastRawInputEntity, rawEntity)) {\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 entity for future comparisons\n this.lastRawInputEntity = rawEntity;\n\n return true;\n }\n\n register(collection: CollectionConfig, rawCollection?: CollectionConfig) {\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: CollectionConfig, rawCollection: CollectionConfig) {\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: CollectionConfig): CollectionConfig {\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 CollectionConfig;\n\n // 0. Resolve and stamp `dataSource` and `engine` on the normalized copy.\n // After this block every normalized collection has both fields set,\n // so downstream code can read them directly without calling\n // `resolveDataSource()`. Only the normalized layer is affected —\n // the raw layer used by the collection editor keeps the author's\n // original fields.\n {\n const resolved = resolveDataSource(result, this.dataSources);\n if (!result.dataSource) (result as { dataSource?: string }).dataSource = resolved.key;\n if (!result.engine) (result as { engine?: string }).engine = resolved.engine;\n }\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;\n const manualRelations = getDataSourceCapabilities(result.engine).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.engine).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 as EngineProperties;\n\n // Populate childCollections from driver-specific fields\n if (!result.childCollections) {\n const capabilities = getDataSourceCapabilities(result.engine);\n const declaredSubcollections = getDeclaredSubcollections(result);\n if (capabilities.supportsSubcollections && declaredSubcollections) {\n result.childCollections = declaredSubcollections;\n } else if (capabilities.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): CollectionConfig | 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): CollectionConfig | 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): CollectionConfig | 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.engine).supportsRelations) {\n throw new Error(`Relation path navigation requires a collection that supports relations, but '${currentCollection.slug}' uses engine '${currentCollection.engine}'`);\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(): CollectionConfig[] {\n if (!this.cachedCollectionsList) {\n this.cachedCollectionsList = Array.from(this.collectionsByTableName.values());\n }\n return this.cachedCollectionsList;\n }\n\n getRawCollections(): CollectionConfig[] {\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: CollectionConfig[],\n entityIds: (string | number)[],\n finalCollection: CollectionConfig\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: CollectionConfig[] = [];\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: CollectionConfig[] | 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: CollectionConfig | 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 { defineCollection } from \"../util/builders\";\n\n/**\n * Default users collection.\n *\n * Prepended to the developer's collections array by the admin and server.\n * Slug-based dedup (Map keyed by slug, last-write-wins) lets developers\n * override by defining their own collection with `slug: \"users\"`.\n */\nexport const defaultUsersCollection = defineCollection({\n name: \"Users\",\n singularName: \"User\",\n slug: \"users\",\n auth: true,\n table: \"users\",\n schema: \"rebase\",\n icon: \"Users\",\n group: \"Settings\",\n openEntityMode: \"dialog\",\n disableDefaultActions: [\"copy\"],\n securityRules: [\n { operation: \"select\",\nroles: [\"admin\"] },\n { operations: [\"insert\", \"update\", \"delete\"],\nroles: [\"admin\"] }\n ],\n sort: [\"createdAt\", \"desc\"],\n properties: {\n id: {\n name: \"ID\",\n type: \"string\",\n isId: \"uuid\",\n ui: { readOnly: true }\n },\n email: {\n name: \"Email\",\n type: \"string\",\n validation: { required: true,\nunique: true }\n },\n displayName: {\n name: \"Name\",\n type: \"string\",\n columnName: \"display_name\",\n validation: { required: true }\n },\n photoURL: {\n name: \"Photo URL\",\n type: \"string\",\n columnName: \"photo_url\",\n ui: { url: \"image\" }\n },\n roles: {\n name: \"Roles\",\n type: \"array\",\n columnType: \"text[]\",\n of: {\n name: \"Role\",\n type: \"string\",\n enum: {\n admin: \"Admin\",\n editor: \"Editor\",\n viewer: \"Viewer\"\n }\n }\n },\n passwordHash: {\n name: \"Password Hash\",\n type: \"string\",\n columnName: \"password_hash\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerified: {\n name: \"Email Verified\",\n type: \"boolean\",\n columnName: \"email_verified\",\n defaultValue: false,\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerificationToken: {\n name: \"Email Verification Token\",\n type: \"string\",\n columnName: \"email_verification_token\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n emailVerificationSentAt: {\n name: \"Email Verification Sent At\",\n type: \"date\",\n columnName: \"email_verification_sent_at\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n metadata: {\n name: \"Metadata\",\n type: \"map\",\n keyValue: true,\n properties: {},\n defaultValue: {},\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n },\n createdAt: {\n name: \"Created At\",\n type: \"date\",\n columnName: \"created_at\",\n autoValue: \"on_create\",\n ui: { readOnly: true }\n },\n updatedAt: {\n name: \"Updated At\",\n type: \"date\",\n columnName: \"updated_at\",\n autoValue: \"on_update\",\n ui: { hideFromCollection: true,\ndisabled: { hidden: true } }\n }\n },\n listProperties: [\"displayName\", \"email\", \"roles\", \"createdAt\"],\n propertiesOrder: [\"id\", \"email\", \"displayName\", \"roles\", \"createdAt\"]\n});\n","import {\n CollectionAccessor,\n FilterCondition,\n FindParams,\n FindResponse,\n LogicalCondition,\n QueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} 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: WhereFilterOp, 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: WhereFilterOp, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, 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: [WhereFilterOp, 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 [WhereFilterOp, unknown][]).push(condition);\n } else {\n // Convert existing single tuple/value into array of tuples\n let firstCondition: [WhereFilterOp, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [WhereFilterOp, 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, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = [column, direction];\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","/**\n * REST wire-format adapter for the unified filter system.\n *\n * This module is the ONLY code in the entire codebase that knows about\n * PostgREST-style dot-syntax strings (`eq.active`, `gt.18`, `in.(a,b)`).\n * Everything else speaks `FilterValues` exclusively.\n *\n * Wire-format values are always strings — the wire format carries no type\n * metadata, so type coercion is the responsibility of the server-side data\n * driver which has access to the collection schema.\n *\n * Commas inside list values are backslash-escaped (`\\,`), and literal\n * backslashes are escaped as `\\\\`.\n *\n * @module\n */\n\nimport {\n WhereFilterOp,\n FilterValues,\n CANONICAL_TO_REST,\n REST_TO_CANONICAL,\n RestFilterOp,\n toCanonicalOp,\n LogicalCondition,\n FilterCondition,\n NULL_OPS\n} from \"@rebasepro/types\";\n\n// ---------------------------------------------------------------------------\n// Value stringification\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a JS value to its querystring representation.\n * `null` is serialized as the literal string `\"null\"`.\n */\nfunction stringifyValue(value: unknown): string {\n if (value === null) return \"null\";\n return String(value);\n}\n\n// ---------------------------------------------------------------------------\n// Comma escaping for list values\n// ---------------------------------------------------------------------------\n\n/**\n * Escape a single list item for the wire format.\n * `\\` → `\\\\`, `,` → `\\,`\n */\nfunction escapeListItem(value: string): string {\n return value.replace(/\\\\/g, \"\\\\\\\\\").replace(/,/g, \"\\\\,\");\n}\n\n/**\n * Unescape a single list item from the wire format.\n * `\\\\` → `\\`, `\\,` → `,`\n */\nfunction unescapeListItem(value: string): string {\n let result = \"\";\n for (let i = 0; i < value.length; i++) {\n if (value[i] === \"\\\\\" && i + 1 < value.length) {\n result += value[i + 1];\n i++; // skip next char\n } else {\n result += value[i];\n }\n }\n return result;\n}\n\n/**\n * Split a parenthesized list string on unescaped commas.\n * Input is the content between `(` and `)`.\n *\n * @example\n * splitListItems(\"admin,editor\") // [\"admin\", \"editor\"]\n * splitListItems(\"hello\\\\, world,foo\") // [\"hello, world\", \"foo\"]\n */\nfunction splitListItems(inner: string): string[] {\n const items: string[] = [];\n let current = \"\";\n for (let i = 0; i < inner.length; i++) {\n if (inner[i] === \"\\\\\" && i + 1 < inner.length) {\n // Escaped character — consume both chars\n current += inner[i] + inner[i + 1];\n i++;\n } else if (inner[i] === \",\") {\n items.push(unescapeListItem(current));\n current = \"\";\n } else {\n current += inner[i];\n }\n }\n items.push(unescapeListItem(current));\n return items;\n}\n\n// ---------------------------------------------------------------------------\n// Typed operator map lookups (no `as any`)\n// ---------------------------------------------------------------------------\n\nconst REST_OP_LOOKUP = REST_TO_CANONICAL as Readonly<Record<string, WhereFilterOp | undefined>>;\nconst CANONICAL_OP_LOOKUP = CANONICAL_TO_REST as Readonly<Record<string, RestFilterOp | undefined>>;\n\n// ---------------------------------------------------------------------------\n// Serialize: FilterValues → REST querystring\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a single canonical condition tuple to a PostgREST dot-string.\n *\n * Throws `TypeError` if the input is not a valid `[WhereFilterOp, unknown]` tuple.\n *\n * @example\n * serializeTuple([\"==\", \"active\"]) // \"eq.active\"\n * serializeTuple([\"in\", [\"admin\",\"editor\"]]) // \"in.(admin,editor)\"\n * serializeTuple([\">=\", 18]) // \"gte.18\"\n */\nfunction serializeTuple(tuple: [WhereFilterOp, unknown]): string {\n if (!Array.isArray(tuple) || tuple.length !== 2) {\n throw new TypeError(\n `serializeTuple: expected a [WhereFilterOp, value] tuple, got ${JSON.stringify(tuple)}`\n );\n }\n\n const [op, value] = tuple;\n\n if (typeof op !== \"string\") {\n throw new TypeError(\n `serializeTuple: operator must be a string, got ${typeof op}`\n );\n }\n\n const restOp = CANONICAL_OP_LOOKUP[op];\n if (!restOp) {\n throw new TypeError(\n `serializeTuple: unknown operator \"${op}\". Valid operators: ${Object.keys(CANONICAL_TO_REST).join(\", \")}`\n );\n }\n\n if (Array.isArray(value)) {\n const items = value.map(v => escapeListItem(stringifyValue(v))).join(\",\");\n return `${restOp}.(${items})`;\n }\n\n return `${restOp}.${stringifyValue(value)}`;\n}\n\n/**\n * Convert `FilterValues` (or `WireFilterValues`) to a PostgREST-style\n * querystring record.\n *\n * - Canonical `[WhereFilterOp, value]` tuples are serialized strictly.\n * - Pre-serialized PostgREST strings (e.g. `\"eq.published\"`) are passed through.\n * - Single conditions produce a string value.\n * - Multiple conditions on the same field produce a string array (repeated params).\n *\n * @example\n * serializeFilter({ status: [\"==\", \"active\"] })\n * // → { status: \"eq.active\" }\n *\n * serializeFilter({ age: [[\">=\", 18], [\"<\", 65]] })\n * // → { age: [\"gte.18\", \"lt.65\"] }\n *\n * // Pre-serialized strings pass through unchanged:\n * serializeFilter({ status: \"eq.published\" })\n * // → { status: \"eq.published\" }\n */\nexport function serializeFilter(\n filter: FilterValues<string> | Record<string, unknown>\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n\n for (const [field, condition] of Object.entries(filter)) {\n if (condition === undefined) continue;\n\n // Pre-serialized PostgREST string — pass through unchanged.\n // This supports WireFilterValues where values may already be\n // serialized dot-strings like \"eq.active\" or raw strings like \"true\".\n if (typeof condition === \"string\") {\n result[field] = condition;\n continue;\n }\n\n // Multiple conditions on the same field: array of tuples\n // We detect this by checking if the first element is also an array.\n if (Array.isArray(condition) && condition.length > 0 && Array.isArray(condition[0])) {\n result[field] = (condition as [WhereFilterOp, unknown][]).map(serializeTuple);\n } else {\n // Single condition — must be a [WhereFilterOp, value] tuple\n result[field] = serializeTuple(condition as [WhereFilterOp, unknown]);\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Deserialize: REST querystring → FilterValues\n// ---------------------------------------------------------------------------\n\n/**\n * Parse a single PostgREST dot-string into a `[WhereFilterOp, unknown]` tuple.\n *\n * All values are returned as strings — the wire format carries no type\n * metadata, so coercion is the data driver's responsibility.\n *\n * If the string doesn't match a known operator prefix, it falls back to\n * `[\"==\", originalString]` (treating the whole string as an equality value).\n * This intentional defense handles values like `\"user@host.com\"` or\n * `\"1.2.3\"` that happen to contain dots.\n */\nfunction deserializeSingle(raw: string): [WhereFilterOp, unknown] {\n const dotIndex = raw.indexOf(\".\");\n if (dotIndex === -1) {\n // No dot → equality on the raw value (kept as string)\n return [\"==\", raw];\n }\n\n const prefix = raw.substring(0, dotIndex);\n const rest = raw.substring(dotIndex + 1);\n\n // Check if the prefix is a known REST operator.\n // This is the key defense against values like \"eq.something\" or \"gt.foo\"\n // being misinterpreted — only known REST short-codes are treated as operators.\n const canonicalOp = REST_OP_LOOKUP[prefix];\n if (!canonicalOp) {\n // Not a known operator (e.g., email \"user@host.com\" or version \"1.2.3\")\n // Treat the entire string as an equality value\n return [\"==\", raw];\n }\n\n // Null-testing operators ignore their serialized value — normalize to null\n // so the tuple round-trips stably (`isnull.null` → [\"is-null\", null]).\n if (NULL_OPS.has(canonicalOp)) {\n return [canonicalOp, null];\n }\n\n // Parse list values: \"(admin,editor)\" → [\"admin\", \"editor\"]\n if (rest.startsWith(\"(\") && rest.endsWith(\")\")) {\n const items = splitListItems(rest.slice(1, -1));\n return [canonicalOp, items];\n }\n\n return [canonicalOp, rest];\n}\n\n/**\n * Convert a PostgREST-style querystring record to `FilterValues`.\n *\n * - String values are parsed as single conditions.\n * - String arrays (repeated query params) become multiple conditions on the same field.\n *\n * @example\n * deserializeFilter({ status: \"eq.active\" })\n * // → { status: [\"==\", \"active\"] }\n *\n * deserializeFilter({ age: [\"gte.18\", \"lt.65\"] })\n * // → { age: [[\">=\", \"18\"], [\"<\", \"65\"]] }\n */\nexport function deserializeFilter(\n query: Record<string, unknown>\n): FilterValues<string> {\n const result: FilterValues<string> = {};\n\n for (const [field, raw] of Object.entries(query)) {\n if (raw === undefined) continue;\n\n // If it's already a canonical tuple [op, value], keep it as is\n if (Array.isArray(raw) && raw.length === 2 && typeof raw[0] === \"string\" && toCanonicalOp(raw[0]) === raw[0]) {\n result[field] = raw as [WhereFilterOp, unknown];\n continue;\n }\n\n if (Array.isArray(raw)) {\n if (raw.length === 0) continue;\n \n // Check if it's an array of canonical tuples\n if (Array.isArray(raw[0]) && raw[0].length === 2 && typeof raw[0][0] === \"string\" && toCanonicalOp(raw[0][0]) === raw[0][0]) {\n result[field] = raw as [WhereFilterOp, unknown][];\n continue;\n }\n\n if (raw.length === 1) {\n result[field] = typeof raw[0] === \"string\" ? deserializeSingle(raw[0]) : [\"==\", raw[0]];\n } else {\n // If the elements are strings, they might be PostgREST dot-strings (repeated params)\n if (typeof raw[0] === \"string\" && raw[0].includes(\".\")) {\n result[field] = raw.map(r => typeof r === \"string\" ? deserializeSingle(r) : ([\"==\", r] as [WhereFilterOp, unknown])) as [WhereFilterOp, unknown][];\n } else {\n // Otherwise assume it's a list of values for an implicit \"in\" or just multiple conditions\n result[field] = [\"in\", raw];\n }\n }\n } else if (typeof raw === \"string\") {\n result[field] = deserializeSingle(raw);\n } else {\n result[field] = [\"==\", raw];\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Logical conditions: serialize / deserialize\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a `LogicalCondition` or `FilterCondition` to its wire-format string.\n *\n * @example\n * serializeLogicalCondition({ column: \"status\", operator: \"==\", value: \"active\" })\n * // → \"status.eq.active\"\n *\n * serializeLogicalCondition({ type: \"or\", conditions: [...] })\n * // → \"or(status.eq.active,status.eq.pending)\"\n */\nexport function serializeLogicalCondition(\n cond: LogicalCondition | FilterCondition\n): string {\n if (\"type\" in cond) {\n // LogicalCondition (and/or)\n const inner = (cond.conditions ?? [])\n .map(serializeLogicalCondition)\n .join(\",\");\n return `${cond.type}(${inner})`;\n }\n\n // FilterCondition\n const restOp = CANONICAL_OP_LOOKUP[cond.operator] ?? \"eq\";\n if (Array.isArray(cond.value)) {\n const items = cond.value.map(v => escapeListItem(stringifyValue(v))).join(\",\");\n return `${cond.column}.${restOp}.(${items})`;\n }\n return `${cond.column}.${restOp}.${stringifyValue(cond.value)}`;\n}\n\n/**\n * Parse a logical condition wire-format string back into a\n * `LogicalCondition` or `FilterCondition`.\n *\n * @example\n * deserializeLogicalCondition(\"status.eq.active\")\n * // → { column: \"status\", operator: \"==\", value: \"active\" }\n *\n * deserializeLogicalCondition(\"or(status.eq.active,age.gte.18)\")\n * // → { type: \"or\", conditions: [...] }\n */\nexport function deserializeLogicalCondition(\n str: string\n): LogicalCondition | FilterCondition {\n // Check for logical group: \"and(...)\" or \"or(...)\"\n const logicalMatch = str.match(/^(and|or)\\((.+)\\)$/);\n if (logicalMatch) {\n const type = logicalMatch[1] as \"and\" | \"or\";\n const innerStr = logicalMatch[2];\n\n // Split on commas that are not inside parentheses\n const conditions: (LogicalCondition | FilterCondition)[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < innerStr.length; i++) {\n if (innerStr[i] === \"(\") depth++;\n else if (innerStr[i] === \")\") depth--;\n else if (innerStr[i] === \",\" && depth === 0) {\n conditions.push(deserializeLogicalCondition(innerStr.slice(start, i)));\n start = i + 1;\n }\n }\n conditions.push(deserializeLogicalCondition(innerStr.slice(start)));\n\n return { type, conditions };\n }\n\n // FilterCondition: \"column.op.value\"\n const firstDot = str.indexOf(\".\");\n if (firstDot === -1) {\n return { column: str, operator: \"==\", value: true };\n }\n\n const column = str.substring(0, firstDot);\n const rest = str.substring(firstDot + 1);\n\n const secondDot = rest.indexOf(\".\");\n if (secondDot === -1) {\n // \"column.value\" — treat as equality (value kept as string)\n return { column, operator: \"==\", value: rest };\n }\n\n const opStr = rest.substring(0, secondDot);\n const valueStr = rest.substring(secondDot + 1);\n const operator = toCanonicalOp(opStr) ?? \"==\";\n\n // Parse list values with escape-aware splitting\n if (valueStr.startsWith(\"(\") && valueStr.endsWith(\")\")) {\n const items = splitListItems(valueStr.slice(1, -1));\n return { column, operator, value: items };\n }\n\n return { column, operator, value: valueStr };\n}\n","import {\n CollectionAccessor,\n DataDriver,\n Entity,\n EntityValues,\n FindParams,\n FindResponse,\n FindResult,\n LogicalCondition,\n RebaseData,\n RebaseSdkData,\n SDKCollectionClient,\n SDKQueryBuilderInterface,\n WhereFilterOp,\n WhereValue\n} from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\nimport { QueryBuilder } from \"./query_builder\";\nimport { deserializeFilter } from \"./filter-dialect\";\n\n/**\n * Convert a flat REST record (e.g. from RestFetchService) to Entity<M> format.\n * Mirrors the client SDK's rowToEntity conversion.\n */\nfunction rowToEntity<M extends Record<string, unknown>>(row: Record<string, unknown>, slug: string): Entity<M> {\n return {\n id: row.id as string | number,\n path: slug,\n values: row as EntityValues<M>\n };\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 // Ensure filters are in canonical [op, value] format even if passed as PostgREST strings\n const filter = params?.where ? deserializeFilter(params.where as Record<string, unknown>) : undefined;\n const limit = params?.limit ?? 20;\n const offset = params?.offset ?? 0;\n\n // Use the RestFetchService for include-aware queries when available\n const fetchService = driver.restFetchService;\n const rows = (fetchService && params?.include && params.include.length > 0)\n ? await fetchService.fetchCollectionForRest(\n slug,\n {\n filter,\n limit: params?.limit,\n offset: params?.offset,\n orderBy: params?.orderBy?.[0],\n order: params?.orderBy?.[1],\n searchString: params?.searchString\n },\n params.include\n )\n : await driver.fetchCollection<M>({\n path: slug,\n limit: params?.limit,\n offset: params?.offset,\n filter,\n orderBy: params?.orderBy?.[0],\n order: params?.orderBy?.[1],\n searchString: params?.searchString\n });\n\n // Compute real total when count is available\n let total = rows.length + offset;\n let hasMore = rows.length >= limit;\n if (driver.count) {\n total = await driver.count({ path: slug, filter });\n hasMore = offset + rows.length < total;\n }\n\n return {\n data: rows.map((row: Record<string, unknown>) => rowToEntity<M>(row, slug)),\n meta: { total, limit, offset, hasMore }\n };\n },\n\n async findById(id: string | number): Promise<Entity<M> | undefined> {\n const row = await driver.fetchOne<M>({ path: slug, id: id });\n return row ? rowToEntity<M>(row, slug) : undefined;\n },\n\n async create(data: Partial<EntityValues<M>>, id?: string | number): Promise<Entity<M>> {\n const row = await driver.save<M>({\n path: slug,\n values: data,\n id: id,\n status: \"new\"\n });\n return rowToEntity<M>(row, slug);\n },\n\n async update(id: string | number, data: Partial<EntityValues<M>>): Promise<Entity<M>> {\n const row = await driver.save<M>({\n path: slug,\n values: data,\n id: id,\n status: \"existing\"\n });\n return rowToEntity<M>(row, slug);\n },\n\n async delete(id: string | number): Promise<void> {\n return driver.delete({\n row: { id,\npath: slug,\nvalues: {} as Record<string, unknown> }\n });\n },\n\n count: driver.count\n ? async (params?: FindParams): Promise<number> => {\n const filter = params?.where ? deserializeFilter(params.where as Record<string, unknown>) : undefined;\n return driver.count!({\n path: slug,\n filter\n });\n }\n : undefined,\n\n listen: driver.listenCollection\n ? (params: FindParams | undefined, onUpdate: (response: FindResponse<M>) => void, onError?: (error: Error) => void) => {\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: params?.where,\n orderBy: params?.orderBy?.[0],\n order: params?.orderBy?.[1],\n searchString: params?.searchString,\n onUpdate: (entities) => {\n onUpdate({\n data: entities.map((row: Record<string, unknown>) => rowToEntity<M>(row, slug)),\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.listenOne\n ? (id: string | number, onUpdate: (entity: Entity<M> | undefined) => void, onError?: (error: Error) => void) => {\n return driver.listenOne!<M>({\n path: slug,\n id: id,\n onUpdate: (entity) => onUpdate(entity ? rowToEntity<M>(entity, slug) : undefined),\n onError\n });\n } : undefined,\n\n // Fluent Query Builder\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, 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: [\"==\", \"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\n// =============================================================================\n// SDK data — flat rows (symmetric with the frontend SDK client)\n// =============================================================================\n\n/**\n * Unwrap a Entity into a flat row. `rowToEntity` stores the whole flat row\n * (id included) under `.values`, so this is just that payload.\n */\nfunction entityToRow<M extends Record<string, unknown>>(entity: Entity<M>): M {\n return entity.values as unknown as M;\n}\n\n/**\n * Fluent query builder for the flat SDK data layer. Mirrors {@link QueryBuilder}\n * but resolves to `FindResult<M>` (flat rows) instead of Entity-wrapped\n * `FindResponse<M>`.\n */\nclass SdkQueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements SDKQueryBuilderInterface<M> {\n private params: FindParams = { where: {} };\n\n constructor(private client: SDKCollectionClient<M>) {}\n\n where<K extends keyof M & string>(column: K, operator: WhereFilterOp, value: WhereValue<M[K]>): this;\n where(logicalCondition: LogicalCondition): this;\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown): this {\n if (typeof columnOrCondition === \"object\" && columnOrCondition !== null && \"type\" in columnOrCondition) {\n this.params.logical = columnOrCondition as LogicalCondition;\n return this;\n }\n if (!this.params.where) this.params.where = {};\n const column = columnOrCondition as string;\n const condition: [WhereFilterOp, unknown] = [operator!, value];\n const existing = this.params.where[column];\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 [WhereFilterOp, unknown][]).push(condition);\n } else {\n let firstCondition: [WhereFilterOp, unknown];\n if (Array.isArray(existing) && existing.length === 2 && typeof existing[0] === \"string\") {\n firstCondition = existing as [WhereFilterOp, unknown];\n } else {\n firstCondition = [\"==\", existing];\n }\n this.params.where[column] = [firstCondition, condition];\n }\n return this;\n }\n\n orderBy(column: keyof M & string, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.params.orderBy = [column, direction];\n return this;\n }\n\n limit(count: number): this { this.params.limit = count; return this; }\n offset(count: number): this { this.params.offset = count; return this; }\n search(searchString: string): this { this.params.searchString = searchString; return this; }\n include(...relations: string[]): this { this.params.include = relations; return this; }\n\n async find(): Promise<FindResult<M>> {\n return this.client.find(this.params);\n }\n\n async count(): Promise<number> {\n return this.client.count ? this.client.count(this.params) : 0;\n }\n\n listen(onUpdate: (data: FindResult<M>) => void, onError?: (error: Error) => void): () => void {\n if (!this.client.listen) {\n throw new Error(\"Listen is only available when the driver supports realtime.\");\n }\n return this.client.listen(this.params, onUpdate, onError);\n }\n}\n\n/**\n * Wrap a Entity-shaped {@link CollectionAccessor} into a flat\n * {@link SDKCollectionClient}. Every returned record is unwrapped to a flat row\n * so the backend SDK is byte-for-byte the same shape as the frontend client.\n */\nfunction toSdkCollectionClient<M extends Record<string, unknown>>(\n snap: CollectionAccessor<M>\n): SDKCollectionClient<M> {\n const client: SDKCollectionClient<M> = {\n async find(params?: FindParams): Promise<FindResult<M>> {\n const res = await snap.find(params);\n return { data: res.data.map(entityToRow), meta: res.meta };\n },\n async findById(id: string | number): Promise<M | undefined> {\n const s = await snap.findById(id);\n return s ? entityToRow(s) : undefined;\n },\n async create(data: Partial<M>, id?: string | number): Promise<M> {\n return entityToRow(await snap.create(data as Partial<EntityValues<M>>, id));\n },\n async update(id: string | number, data: Partial<M>): Promise<M> {\n return entityToRow(await snap.update(id, data as Partial<EntityValues<M>>));\n },\n delete(id: string | number): Promise<void> {\n return snap.delete(id);\n },\n count: snap.count ? (params?: FindParams) => snap.count!(params) : undefined,\n listen: snap.listen\n ? (params: FindParams | undefined, onUpdate: (r: FindResult<M>) => void, onError?: (e: Error) => void) =>\n snap.listen!(params, (res) => onUpdate({ data: res.data.map(entityToRow), meta: res.meta }), onError)\n : undefined,\n listenById: snap.listenById\n ? (id: string | number, onUpdate: (r: M | undefined) => void, onError?: (e: Error) => void) =>\n snap.listenById!(id, (s) => onUpdate(s ? entityToRow(s) : undefined), onError)\n : undefined,\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, value?: unknown) {\n const builder = new SdkQueryBuilder<M>(client);\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, direction?: \"asc\" | \"desc\") => new SdkQueryBuilder<M>(client).orderBy(column, direction),\n limit: (count: number) => new SdkQueryBuilder<M>(client).limit(count),\n offset: (count: number) => new SdkQueryBuilder<M>(client).offset(count),\n search: (searchString: string) => new SdkQueryBuilder<M>(client).search(searchString),\n include: (...relations: string[]) => new SdkQueryBuilder<M>(client).include(...relations)\n };\n return client;\n}\n\n/**\n * Wrap a flat {@link SDKCollectionClient} into a Entity-shaped\n * {@link CollectionAccessor}. Every returned row is re-wrapped into the\n * `{ id, path, values }` view-model the admin CMS renders.\n */\nfunction toEntityAccessor<M extends Record<string, unknown>>(\n sdk: SDKCollectionClient<M>,\n slug: string\n): CollectionAccessor<M> {\n const accessor: CollectionAccessor<M> = {\n async find(params?: FindParams): Promise<FindResponse<M>> {\n const res = await sdk.find(params);\n return { data: res.data.map((row) => rowToEntity<M>(row, slug)), meta: res.meta };\n },\n async findById(id: string | number): Promise<Entity<M> | undefined> {\n const row = await sdk.findById(id);\n return row ? rowToEntity<M>(row, slug) : undefined;\n },\n async create(data: Partial<EntityValues<M>>, id?: string | number): Promise<Entity<M>> {\n return rowToEntity<M>(await sdk.create(data as Partial<M>, id), slug);\n },\n async update(id: string | number, data: Partial<EntityValues<M>>): Promise<Entity<M>> {\n const row = await sdk.update(id, data as Partial<M>);\n if (!row) throw new Error(`Update returned no data for id ${id}`);\n return rowToEntity<M>(row, slug);\n },\n delete(id: string | number): Promise<void> {\n return sdk.delete(id);\n },\n count: sdk.count ? (params?: FindParams) => sdk.count!(params) : undefined,\n listen: sdk.listen\n ? (params: FindParams | undefined, onUpdate: (r: FindResponse<M>) => void, onError?: (e: Error) => void) =>\n sdk.listen!(params, (res) => onUpdate({ data: res.data.map((row) => rowToEntity<M>(row, slug)), meta: res.meta }), onError)\n : undefined,\n listenById: sdk.listenById\n ? (id: string | number, onUpdate: (s: Entity<M> | undefined) => void, onError?: (e: Error) => void) =>\n sdk.listenById!(id, (row) => onUpdate(row ? rowToEntity<M>(row, slug) : undefined), onError)\n : undefined,\n where(columnOrCondition: string | LogicalCondition, operator?: WhereFilterOp, 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, direction?: \"asc\" | \"desc\") => new QueryBuilder<M>(accessor).orderBy(column, direction),\n limit: (count: number) => new QueryBuilder<M>(accessor).limit(count),\n offset: (count: number) => new QueryBuilder<M>(accessor).offset(count),\n search: (searchString: string) => new QueryBuilder<M>(accessor).search(searchString),\n include: (...relations: string[]) => new QueryBuilder<M>(accessor).include(...relations)\n };\n return accessor;\n}\n\n/**\n * Wrap a flat {@link RebaseSdkData} into a Entity-shaped {@link RebaseData}.\n *\n * This is the **CMS boundary**: the SDK client (`client.data`) returns flat\n * rows, but the admin renders the `Entity` view-model (`entity.values.*`).\n * `core/Rebase.tsx` wraps `client.data` through this before handing it to the\n * CMS `RebaseDataContext` — without it the admin renders rows with only their\n * `id`.\n */\nexport function wrapAsEntityData(sdkData: RebaseSdkData): 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 = toEntityAccessor(sdkData.collection(slug), slug);\n cache.set(slug, accessor);\n }\n return accessor;\n }\n\n const target = { collection: getAccessor } as RebaseData;\n\n return new Proxy(target, {\n get(_target, prop: string | symbol) {\n if (prop === \"collection\") return getAccessor;\n if (typeof prop === \"symbol\") return undefined;\n if (prop === \"then\" || prop === \"toJSON\" || prop === \"$$typeof\") return undefined;\n return getAccessor(toSnakeCase(prop));\n }\n });\n}\n\n/**\n * Wrap a Entity-shaped {@link RebaseData} into a flat {@link RebaseSdkData}.\n *\n * Every collection accessor is adapted to return flat rows. Use this to derive\n * the flat SDK data layer (`context.data`) from an existing Entity data layer\n * — e.g. the admin routes its Entity data via `useData()` and exposes the\n * same routing as flat `context.data` for callbacks by wrapping it here.\n */\nexport function wrapAsSdkData(entityData: RebaseData): RebaseSdkData {\n const cache = new Map<string, SDKCollectionClient>();\n\n function getAccessor(slug: string): SDKCollectionClient {\n let accessor = cache.get(slug);\n if (!accessor) {\n accessor = toSdkCollectionClient(entityData.collection(slug));\n cache.set(slug, accessor);\n }\n return accessor;\n }\n\n const target = { collection: getAccessor } as RebaseSdkData;\n\n return new Proxy(target, {\n get(_target, prop: string | symbol) {\n if (prop === \"collection\") return getAccessor;\n if (typeof prop === \"symbol\") return undefined;\n if (prop === \"then\" || prop === \"toJSON\" || prop === \"$$typeof\") return undefined;\n return getAccessor(toSnakeCase(prop));\n }\n });\n}\n\n/**\n * Build a flat {@link RebaseSdkData} from a `DataDriver`.\n *\n * This is the developer-facing SDK data layer used by backend framework\n * callbacks & scripts (`context.data` / `rebase.data`). It returns flat rows —\n * identical in shape to the frontend SDK client — so the API is symmetric\n * across front and back. The admin CMS uses {@link buildRebaseData} (Entity).\n */\nexport function buildSdkData(driver: DataDriver): RebaseSdkData {\n return wrapAsSdkData(buildRebaseData(driver));\n}\n","import { RebaseData, RebaseSdkData } from \"@rebasepro/types\";\nimport { toSnakeCase } from \"@rebasepro/utils\";\n\n/**\n * The two data-layer shapes that can be routed: the Entity-shaped admin\n * {@link RebaseData} or the flat SDK {@link RebaseSdkData}. Both expose a\n * `.collection(slug)` accessor, which is all the router needs.\n */\nexport type RoutableData = RebaseData | RebaseSdkData;\n\n/**\n * Parameters for {@link buildRoutedRebaseData}.\n */\nexport interface RoutedRebaseDataParams<T extends RoutableData = RebaseData> {\n /**\n * The default data source. Handles every collection that does not\n * resolve to an entry in `sources` (i.e. server-transport collections,\n * which ride the Rebase client).\n */\n defaultData: T;\n\n /**\n * Per-data-source instances for direct and custom transports, keyed by\n * data-source key (e.g. `\"analytics\"`). Server-mediated sources are not\n * listed here — they fall through to `defaultData`.\n */\n sources: Record<string, T>;\n\n /**\n * Resolve the data-source key for a given collection slug or path.\n * Typically backed by the collection registry + `resolveDataSource`\n * (`resolveDataSource(registry.getCollection(path), defs).key`).\n *\n * Return `undefined` (or a key absent from `sources`) to route to the\n * default data source.\n */\n resolveKey: (slugOrPath: string) => string | undefined;\n}\n\n/**\n * Build a {@link RebaseData} that routes each collection to the right\n * backend based on its resolved data source.\n *\n * `.collection(path)` (and dynamic `data.products`-style access) resolves the\n * collection's data-source key via `resolveKey` and delegates to the matching\n * entry in `sources`, falling back to `defaultData` when there is no match.\n * Because routing keys off the *path being accessed*, a reference widget\n * inside a Firestore form that points at a Postgres collection is still\n * served by Postgres — routing follows the target, not the ancestor.\n *\n * When `sources` is empty this returns `defaultData` untouched, so the\n * single-driver setup keeps identical behaviour and identity (important for\n * effect dependencies that key off the data instance).\n *\n * @example\n * const data = buildRoutedRebaseData({\n * defaultData: client.data,\n * sources: { analytics: buildRebaseData(firestoreDriver) },\n * resolveKey: (path) => resolveDataSource(registry.getCollection(path), defs).key\n * });\n * await data.products.find(); // → default (server / Postgres)\n * await data.events.find(); // → Firestore, if `events.dataSource === \"analytics\"`\n */\nexport function buildRoutedRebaseData<T extends RoutableData = RebaseData>({\n defaultData,\n sources,\n resolveKey\n}: RoutedRebaseDataParams<T>): T {\n\n // Fast path: nothing to route → return the default untouched (preserves\n // referential identity for effect dependencies).\n if (!sources || Object.keys(sources).length === 0) {\n return defaultData;\n }\n\n function resolve(slugOrPath: string): T {\n const key = resolveKey(slugOrPath);\n if (key && sources[key]) return sources[key];\n return defaultData;\n }\n\n function getAccessor(slugOrPath: string) {\n return (resolve(slugOrPath) as RoutableData).collection(slugOrPath);\n }\n\n const target = {\n collection: getAccessor\n } as unknown as T;\n\n return new Proxy(target as object, {\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, mirroring\n // buildRebaseData so dynamic access routes consistently.\n return getAccessor(toSnakeCase(prop));\n }\n }) as T;\n}\n","import type { OrderByTuple } from \"@rebasepro/types\";\n\n/**\n * Sort-order wire codec.\n *\n * This is the ONLY module that knows about the colon-delimited wire format\n * (`\"field:direction\"`) used in HTTP query parameters.\n * Everything else speaks {@link OrderByTuple} exclusively.\n *\n * Mirrors the filter architecture in `filter-dialect.ts`.\n *\n * @module\n */\n\n/**\n * Serialize an {@link OrderByTuple} to the wire format `\"field:direction\"`.\n *\n * **Runtime tolerance:** if the input is already a well-formed wire string\n * (from an untyped JS caller), it is returned unchanged.\n * This is undocumented tolerance, not public API — don't rely on it.\n *\n * @param orderBy - A canonical `[field, direction]` tuple, or at runtime\n * possibly a pre-serialized string (undocumented tolerance).\n * @returns The wire-format string, or `undefined` if the input is falsy.\n *\n * @remarks\n * Field names containing `:` are representable in the tuple form but\n * **not** on the wire — this is an inherent limitation of the colon-delimited\n * encoding and is not resolved here.\n */\nexport function serializeOrderBy(orderBy?: OrderByTuple | string): string | undefined {\n if (!orderBy) return undefined;\n // Runtime tolerance: pass through a pre-serialized wire string unchanged.\n if (typeof orderBy === \"string\") return orderBy;\n return `${orderBy[0]}:${orderBy[1]}`;\n}\n\n/**\n * Deserialize a wire-format `\"field:direction\"` string into an {@link OrderByTuple}.\n *\n * Lenient parsing (matches existing server behaviour):\n * - Bare field name (no colon): `\"name\"` → `[\"name\", \"asc\"]`\n * - Unknown direction: `\"name:foo\"` → `[\"name\", \"asc\"]`\n * - Empty / falsy input: → `undefined`\n *\n * @param raw - The wire-format string from an HTTP query parameter.\n * @returns The canonical tuple, or `undefined` if the input is empty/falsy.\n */\nexport function deserializeOrderBy(raw?: string): OrderByTuple | undefined {\n if (!raw) return undefined;\n const idx = raw.indexOf(\":\");\n if (idx === -1) return [raw, \"asc\"];\n const field = raw.slice(0, idx);\n const dir = raw.slice(idx + 1);\n return [field, dir === \"desc\" ? \"desc\" : \"asc\"];\n}\n","/**\n * Table Classification\n *\n * Shared constants and pure functions for classifying database tables.\n * Used by both the server-side PostgresBackendDriver and the Studio RLS editor.\n */\n\n/** Possible categories a database table can belong to. */\nexport type TableCategory = \"rebase-internal\" | \"junction\" | \"user\";\n\n/** Schemas that are always considered Rebase-internal. */\nexport const REBASE_INTERNAL_SCHEMAS: readonly string[] = [\"rebase\", \"auth\"];\n\n/** Table-name prefixes that mark a table as Rebase-internal regardless of schema. */\nexport const REBASE_INTERNAL_PREFIXES: readonly string[] = [\n \"_rebase_\",\n \"_auth_\",\n \"drizzle_\",\n];\n\n/**\n * Synchronously classify a table based on naming conventions.\n *\n * @param tableName - The unqualified name of the table.\n * @param schemaName - The schema the table belongs to (e.g. `\"public\"`, `\"rebase\"`).\n * @returns `\"rebase-internal\"` when the table belongs to a reserved schema or\n * carries a reserved prefix; `\"user\"` otherwise.\n *\n * @remarks\n * Junction-table detection requires an async database query and is therefore\n * **not** handled by this function. Use {@link detectJunctionTables} to obtain\n * the set of junction tables, then reclassify as needed.\n */\nexport function classifyTable(\n tableName: string,\n schemaName: string,\n): TableCategory {\n if (\n REBASE_INTERNAL_SCHEMAS.includes(schemaName) ||\n REBASE_INTERNAL_PREFIXES.some((prefix) => tableName.startsWith(prefix))\n ) {\n return \"rebase-internal\";\n }\n\n return \"user\";\n}\n\n/**\n * Convenience predicate that checks whether a table is Rebase-internal.\n *\n * @param tableName - The unqualified name of the table.\n * @param schemaName - The schema the table belongs to.\n * @returns `true` if the table is classified as `\"rebase-internal\"`.\n */\nexport function isRebaseInternalTable(\n tableName: string,\n schemaName: string,\n): boolean {\n return classifyTable(tableName, schemaName) === \"rebase-internal\";\n}\n\n/** SQL query that detects junction tables in the `public` schema. */\nexport const JUNCTION_TABLES_SQL = `\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 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\n/**\n * Asynchronously detect junction (link) tables in the `public` schema.\n *\n * A junction table is defined as a table where **every** column participates in\n * at least one foreign-key constraint.\n *\n * @param executeSql - A callback that executes a raw SQL string and returns the\n * resulting rows.\n * @returns A `Set` containing the names of all detected junction tables.\n */\nexport async function detectJunctionTables(\n executeSql: (sql: string) => Promise<Record<string, unknown>[]>,\n): Promise<Set<string>> {\n const rows = await executeSql(JUNCTION_TABLES_SQL);\n const junctionTables = new Set<string>();\n\n for (const row of rows) {\n if (typeof row.table_name === \"string\") {\n junctionTables.add(row.table_name);\n }\n }\n\n return junctionTables;\n}\n"],"mappings":"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"}
|