import { type GrantedRole } from '@dereekb/model'; import { type Getter, type SetIncludesMode, type ArrayOrValue, type UseAsync, type UsePromiseFunction } from '@dereekb/util'; import { type FirestoreDocument } from '../firestore/accessor/document'; import { type FirestoreModelIdentity, type FirestoreModelKey, type FirestoreModelType, type FirestoreModelTypes, type ReadFirestoreModelKeyInput } from '../firestore/collection/collection'; import { type FirebaseModelCollectionLoader, type FirebaseModelLoader, type InContextFirebaseModelCollectionLoader, type InContextFirebaseModelLoader } from './model/model.loader'; import { type InContextFirebaseModelPermissionService, type FirebasePermissionContext, type FirebaseModelPermissionService, type FirebasePermissionServiceInstanceDelegate, type InModelContextFirebaseModelPermissionService, type FirebasePermissionErrorContext } from './permission'; import { type ContextGrantedModelRolesReader } from './permission/permission.service.role'; /** * Context type required by the model service layer — combines permission and error handling contexts. */ export type FirebaseModelServiceContext = FirebasePermissionContext & FirebasePermissionErrorContext; /** * Unified service for a single Firestore model type that combines permission checking, model loading, and collection access. * * Each model type in the application (e.g., Notification, StorageFile) gets its own {@link FirebaseModelService}. * The service is the central point for CRUD operations that need permission-aware model access. * * @template C - the model context type * @template T - the Firestore document data type * @template D - the FirestoreDocument wrapper type * @template R - the granted role type for this model */ export interface FirebaseModelService = FirestoreDocument, R extends GrantedRole = GrantedRole> extends FirebaseModelPermissionService, FirebaseModelLoader, FirebaseModelCollectionLoader { /** * Whether this model is SERVER-ONLY: unreachable by any client, on any read path. * * See {@link FirebaseModelServiceConfig.serverOnly}. */ readonly serverOnly?: boolean; } /** * Lazy getter for a {@link FirebaseModelService}, typically used in the service factory map. */ export type FirebaseModelServiceGetter = FirestoreDocument, R extends GrantedRole = GrantedRole> = Getter>; /** * Configuration for creating a {@link FirebaseModelService} via {@link firebaseModelService}. * * Provides the collection loader and the role-mapping delegate. Model loading is derived automatically * from the collection loader. */ export interface FirebaseModelServiceConfig = FirestoreDocument, R extends GrantedRole = GrantedRole> extends Omit, 'loadModelForKey'>, FirebaseModelCollectionLoader { /** * Marks this model SERVER-ONLY: no client may read it, on any path. * * `roleMapForModel` and `firestore.rules` are two independent authorization systems, and the * model API runs under the Admin SDK — so it evaluates the former and bypasses the latter * entirely. For a model whose rules file has no match block (or an `allow read: if false`), that * divergence is a LEAK: the rules say server-only, and the model API hands the document to a * client anyway. * * Setting this closes the gap by refusing the read ahead of `useModel`, so both read paths agree. * It is a routing decision, not a permission computation — hence a flag rather than a role. * * Opt-in by design: absent means today's behaviour, which is the backward-compatible direction * for a framework. Downstream apps are unaffected until they set it. */ readonly serverOnly?: boolean; } /** * Creates a {@link FirebaseModelService} that wires together model loading and permission evaluation. * * @param config - Collection loader and role mapping functions. * @returns A {@link FirebaseModelService} combining model loading and permission evaluation. * * @example * ```ts * const notificationService = firebaseModelService({ * getFirestoreCollection: (context) => context.app.notification, * roleMapForModel: (output, context, model) => computeRoles(output, context) * }); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function firebaseModelService = FirestoreDocument, R extends GrantedRole = GrantedRole>(config: FirebaseModelServiceConfig): FirebaseModelService; /** * Cached getter that lazily creates and memoizes a {@link FirebaseModelService}. */ export type FirebaseModelServiceFactory = FirestoreDocument, R extends GrantedRole = GrantedRole> = Getter>; /** * Creates a {@link FirebaseModelServiceFactory} that lazily instantiates and caches the service. * * @param config - The service configuration. * @returns A {@link FirebaseModelServiceFactory} that lazily creates and caches the service. * * @__NO_SIDE_EFFECTS__ */ export declare function firebaseModelServiceFactory = FirestoreDocument, R extends GrantedRole = GrantedRole>(config: FirebaseModelServiceConfig): FirebaseModelServiceFactory; /** * A context-bound model service with permission checking, model loading, and collection access. * * Does not include the `forKey` method — use {@link InContextFirebaseModelService} for the full interface. */ export type LimitedInContextFirebaseModelService = FirestoreDocument, R extends GrantedRole = GrantedRole> = InContextFirebaseModelPermissionService & InContextFirebaseModelLoader & InContextFirebaseModelCollectionLoader & { forKey: (key: FirestoreModelKey) => InModelContextFirebaseModelService; }; /** * Full context-bound model service that can also be called directly with a model/key to get a model-bound service. * * Calling `service(modelOrKey)` returns an {@link InModelContextFirebaseModelService} with role checking and assertions. * Also provides `forKey(key)` for key-based lookup. */ export type InContextFirebaseModelService = FirestoreDocument, R extends GrantedRole = GrantedRole> = InModelContextFirebaseModelServiceFactory & LimitedInContextFirebaseModelService & { /** * Mirrors {@link FirebaseModelServiceConfig.serverOnly}, so a caller holding only the * context-bound service can gate on it without reaching back for the config. */ readonly serverOnly?: boolean; }; /** * Factory that binds a {@link FirebaseModelService} to a specific context, producing an {@link InContextFirebaseModelService}. */ export type InContextFirebaseModelServiceFactory = FirestoreDocument, R extends GrantedRole = GrantedRole> = (context: C) => InContextFirebaseModelService; /** * Factory that binds a context-aware model service to a specific model document or key. */ export type InModelContextFirebaseModelServiceFactory = FirestoreDocument, R extends GrantedRole = GrantedRole> = (modelOrKey: D | FirestoreModelKey) => InModelContextFirebaseModelService; /** * A model service bound to both a context and a specific model document. * * Provides role-based access control via `roleReader()`, `requireRole()`, and `use()`. * Can be called as a function with roles to get a {@link UsePromiseFunction} for the role reader. */ export type InModelContextFirebaseModelService = FirestoreDocument, R extends GrantedRole = GrantedRole> = InModelContextFirebaseModelPermissionService & InModelContextFirebaseModelServiceUseFunction & InContextFirebaseModelCollectionLoader & { roleReader: () => Promise>; requireRole: (roles: ArrayOrValue, setIncludes?: SetIncludesMode) => Promise>; requireUse: InModelContextFirebaseModelServiceUseFunction; use: UsePromiseFunction>; }; export type InModelContextFirebaseModelServiceUseFunction = FirestoreDocument, R extends GrantedRole = GrantedRole> = (roles: ArrayOrValue, setIncludes?: SetIncludesMode) => UsePromiseFunction>; /** * Creates an {@link InContextFirebaseModelServiceFactory} from a service getter. * * The returned factory, when given a context, produces a callable service that can be invoked * with a model or key to perform permission-checked operations. * * @param factory - Lazy getter for the underlying model service. * @returns An {@link InContextFirebaseModelServiceFactory} that binds contexts to the service. * * @__NO_SIDE_EFFECTS__ */ export declare function inContextFirebaseModelServiceFactory = FirestoreDocument, R extends GrantedRole = GrantedRole>(factory: FirebaseModelServiceGetter): InContextFirebaseModelServiceFactory; /** * Map of model type identifiers to their corresponding {@link FirebaseModelServiceGetter} factories. * * Defines the full set of model services available in the application. */ export type FirebaseModelsServiceFactory = { [J in FirestoreModelTypes]: FirebaseModelServiceGetter; }; /** * Provides access to the list of all registered model types. */ export type FirebaseModelsServiceTypesAccessor = { allTypes(): FirestoreModelType[]; }; /** * Multi-model service function that returns a context-bound service for any registered model type. * * Call with a model type key and context to get an {@link InContextFirebaseModelService} for that model. * This is the top-level entry point for permission-checked model operations in server-side code. */ export type FirebaseModelsService, C extends FirebaseModelServiceContext> = ((type: K, context: C) => X[K] extends FirebaseModelServiceGetter ? InContextFirebaseModelService : never) & FirebaseModelsServiceTypesAccessor; /** * Extracts the union of model type keys from a {@link FirebaseModelsService}. */ export type FirebaseModelsServiceTypes> = S extends FirebaseModelsService ? keyof X : never; /** * Creates a new FirebaseModelsService. * * When a context is passed, it is extended and the services are available in the context too as a services function. * * This allows the services function to reference itself in usage. You do this by creating another type that extends the context. Example: * * export type DemoFirebaseBaseContext = FirebaseAppModelContext; * ... * export const demoFirebaseModelServices = firebaseModelsService(DEMO_FIREBASE_MODEL_SERVICE_FACTORIES); * export type DemoFirebaseContext = DemoFirebaseBaseContext & { service: typeof demoFirebaseModelServices }; * * @param services - Map of model service getter factories keyed by model type. * @returns Aggregated {@link FirebaseModelsService} that dispatches by model type. * * @__NO_SIDE_EFFECTS__ */ export declare function firebaseModelsService, C extends FirebaseModelServiceContext, I extends FirestoreModelIdentity = FirestoreModelIdentity>(services: X): FirebaseModelsService; /** * A context-bound multi-model service — call with a model type to get the context-bound single-model service. */ export type InContextFirebaseModelsService = FirebaseModelsServiceTypesAccessor & (Y extends FirebaseModelsService ? (type: K) => X[K] extends FirebaseModelServiceGetter ? InContextFirebaseModelService : never : never); /** * Factory that creates an {@link InContextFirebaseModelsService} from a context. */ export type InContextFirebaseModelsServiceFactory = FirebaseModelsServiceTypesAccessor & (Y extends FirebaseModelsService ? (context: C) => InContextFirebaseModelsService : never); /** * Creates an {@link InContextFirebaseModelsServiceFactory} from a {@link FirebaseModelsService}. * * The returned factory binds a context, so callers can then select individual model services by type. * * @param service - The multi-model service to wrap. * @returns An {@link InContextFirebaseModelsServiceFactory} that binds a context to the service. * * @__NO_SIDE_EFFECTS__ */ export declare function inContextFirebaseModelsServiceFactory, C extends FirebaseModelServiceContext, I extends FirestoreModelIdentity = FirestoreModelIdentity>(service: FirebaseModelsService): InContextFirebaseModelsServiceFactory>; /** * Selection parameters for accessing a specific model by type and key (without role requirements). */ export type FirebaseModelsServiceSelection, T extends FirebaseModelsServiceTypes> = Omit, 'roles' | 'rolesSetIncludes'>; export type FirebaseModelsServiceSelectionResult, T extends FirebaseModelsServiceTypes> = Y extends FirebaseModelsService ? (T extends keyof X ? (X[T] extends FirebaseModelServiceGetter ? InModelContextFirebaseModelService : never) : never) : never; export type FirebaseModelsServiceSelectionResultRolesReader, T extends FirebaseModelsServiceTypes> = Y extends FirebaseModelsService ? (T extends keyof X ? (X[T] extends FirebaseModelServiceGetter ? ContextGrantedModelRolesReader : never) : never) : never; export type FirebaseModelsServiceSelectionResultDocumentType, T extends FirebaseModelsServiceTypes> = Y extends FirebaseModelsService ? (T extends keyof X ? (X[T] extends FirebaseModelServiceGetter ? D : never) : never) : never; export type UseFirebaseModelsServiceSelection, T extends FirebaseModelsServiceTypes> = Y extends FirebaseModelsService ? X extends FirebaseModelsServiceFactory> ? { context: C; key: X[T] extends FirebaseModelServiceGetter ? ReadFirestoreModelKeyInput : ReadFirestoreModelKeyInput; roles?: X[T] extends FirebaseModelServiceGetter ? ArrayOrValue : never; rolesSetIncludes?: SetIncludesMode; } : never : never; export type UseFirebaseModelsServiceSelectionResult, T extends FirebaseModelsServiceTypes> = Y extends FirebaseModelsService ? (T extends keyof X ? (X[T] extends FirebaseModelServiceGetter ? UsePromiseFunction> : never) : never) : never; export type UseFirebaseModelsServiceSelectionUseFunction, T extends FirebaseModelsServiceTypes, O> = Y extends FirebaseModelsService ? (T extends keyof X ? (X[T] extends FirebaseModelServiceGetter ? UseAsync, O> : never) : never) : never; /** * Selects a model-bound service instance from a multi-model service by type and key. * * @param service - The multi-model service. * @param type - The model type to select. * @param select - Selection params including context and key. * @returns The {@link FirebaseModelsServiceSelectionResult} bound to the specified model. * * @__NO_SIDE_EFFECTS__ */ export declare function selectFromFirebaseModelsService, T extends FirebaseModelsServiceTypes>(service: Y, type: T, select: FirebaseModelsServiceSelection): FirebaseModelsServiceSelectionResult; /** * Selects a model-bound service and returns a {@link UsePromiseFunction} that lazily evaluates roles on use. * * If roles are provided, uses `requireUse` to assert them. Otherwise, returns the basic `use` function. * * @param service - The multi-model service. * @param type - The model type to select. * @param select - Selection params including context, key, and optional role requirements. * @returns A {@link UsePromiseFunction} for the resolved roles reader. * * @__NO_SIDE_EFFECTS__ */ export declare function useFirebaseModelsService, T extends FirebaseModelsServiceTypes>(service: Y, type: T, select: UseFirebaseModelsServiceSelection): UseFirebaseModelsServiceSelectionResult; /** * Builds a type map from collection type to {@link FirestoreModelIdentity} for all registered models. * * Useful for routing incoming requests to the correct model service by collection path. * * @param inContextFirebaseModelsService - Context-bound multi-model service. * @returns Map keyed by collection type, valued with the matching {@link FirestoreModelIdentity}. * * @__NO_SIDE_EFFECTS__ */ export declare function buildFirebaseCollectionTypeModelTypeMap>(inContextFirebaseModelsService: InContextFirebaseModelsService): import("..").FirestoreModelIdentityTypeMap;