import { type Maybe } from '@dereekb/util'; import { type FirebaseAuthUserId } from '../../common/auth/auth'; import { type StorageFile } from '../storagefile/storagefile'; import { type FormSpace, type FormSpaceFile, type FormSpaceFirestoreCollections } from './formspace'; import { type FormSpaceFileSlot, type FormSpaceKey } from './formspace.id'; import { type AppFormSpaceTypeConfigService, type FormSpaceFileAccess, type FormSpaceTypeConfig } from './formspace.type'; /** * Input for {@link formSpaceSlotFileAccess}. */ export interface FormSpaceSlotFileAccessInput { readonly config: FormSpaceTypeConfig; readonly slot: Maybe; } /** * Resolves the {@link FormSpaceFileAccess} governing one slot. * * Slot narrows type narrows default, the same precedence `allowedMimeTypes` and `maxFileSizeBytes` use. * * @param input - The type config and the slot. * @returns The effective file access policy. * * @__NO_SIDE_EFFECTS__ */ export declare function formSpaceSlotFileAccess(input: FormSpaceSlotFileAccessInput): FormSpaceFileAccess; /** * Input for {@link formSpaceFileUploaderId}. */ export interface FormSpaceFileUploaderIdInput { readonly formSpace: Pick; readonly file: Pick; } /** * The uid that owns one file for access purposes. * * Falls back to the space's `u` when the entry carries no `ub`. That is not a guess: `ub` was added after * FormSpace shipped, and every entry written before it existed came from the only party that could upload * at the time — the space's own user. Falling back keeps an older single-user space working unchanged * under an `'uploader'` policy instead of locking its owner out of their own files. * * @param input - The space and the file entry. * @returns The uploader's uid. * * @__NO_SIDE_EFFECTS__ */ export declare function formSpaceFileUploaderId(input: FormSpaceFileUploaderIdInput): FirebaseAuthUserId; /** * Input for {@link isFormSpaceFileAccessibleWithAccess}. */ export interface IsFormSpaceFileAccessibleWithAccessInput { readonly fileAccess: FormSpaceFileAccess; readonly formSpace: Pick; readonly file: Pick; readonly uid: Maybe; } /** * THE per-file rule, applied to an ALREADY-RESOLVED {@link FormSpaceFileAccess}. * * Split from {@link isFormSpaceFileAccessibleByUser} so a caller holding the policy but not the whole * `FormSpaceTypeConfig` — a UI handed `fileAccess` as an input, say — decides with the same function the * server enforces with, rather than a second copy of `ub ?? u` that could drift from it. * * @param input - The resolved policy, the space, the file entry, and the caller. * @returns True when the caller may read and remove this file. * * @__NO_SIDE_EFFECTS__ */ export declare function isFormSpaceFileAccessibleWithAccess(input: IsFormSpaceFileAccessibleWithAccessInput): boolean; /** * Input for {@link isFormSpaceFileAccessibleByUser}. */ export interface IsFormSpaceFileAccessibleByUserInput { readonly formSpace: Pick; readonly config: FormSpaceTypeConfig; readonly file: Pick; readonly uid: Maybe; } /** * THE per-file predicate: may this user read or remove this file, given they already reach the space? * * One function for both verbs on purpose. "You can see it but not delete it" and "you can delete it but not * see it" are both worse than either consistent answer, and two policies would be two things to keep in * step. A type that genuinely needs to split them should keep files in separate slots and narrow one. * * @param input - The space, its type config, the file entry, and the caller. * @returns True when the caller may read and remove this file. * * @example * ```ts * const allowed = isFormSpaceFileAccessibleByUser({ formSpace, config, file, uid: context.auth?.uid }); * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function isFormSpaceFileAccessibleByUser(input: IsFormSpaceFileAccessibleByUserInput): boolean; /** * Returns the {@link FormSpaceKey} a StorageFile was uploaded into, or null when it is not a FormSpace file. * * Reads the group ids rather than a dedicated field: a FormSpace upload joins the group * {@link formSpaceStorageFileGroupId} keys by the space's own model key, so the key is already recoverable * and a second copy of it could only drift. The purpose is checked first, so a file from any other pipeline * costs one string comparison. * * Decoded by splitting the FIRST separator rather than through * {@link inferStorageFileGroupRelatedModelKey}, which replaces EVERY `_` with a `/`. That generic inverse is * only two-way for an id that contains no underscore, and a space keyed by {@link formSpaceIdForModel} * always does — a guestbook's album is `fsp/gb_`, which the generic inverse turns into the three-segment * `fsp/gb/`: not a document path at all. FormSpace is a ROOT collection, so everything after the first * separator is the id, underscores and all. * * @param storageFile - The StorageFile to inspect. * @returns The FormSpace's model key, or null. * * @__NO_SIDE_EFFECTS__ */ export declare function formSpaceKeyForStorageFile(storageFile: Pick): Maybe; /** * Input for {@link isFormSpaceStorageFileAccessibleByUser}. */ export interface IsFormSpaceStorageFileAccessibleByUserInput { readonly collections: FormSpaceFirestoreCollections; readonly appFormSpaceTypeConfigService: AppFormSpaceTypeConfigService; readonly storageFile: Pick; readonly uid: Maybe; } /** * {@link isFormSpaceFileAccessibleByUser}, asked from the StorageFile side — where a download is authorized. * * Returns true for a StorageFile that is not a FormSpace upload at all, so a caller can AND it into an * existing role grant without first classifying the file: this narrows FormSpace files and abstains on * everything else. * * Costs at most one FormSpace read, and usually none. A caller who IS the file's `uby` is allowed under * BOTH policies, so the space never has to be loaded to answer for them — which is the common case, since * the person downloading a file is overwhelmingly the person who uploaded it. * * @param input - The collections, the type registry, the StorageFile, and the caller. * @returns True when the caller may read this file. */ export declare function isFormSpaceStorageFileAccessibleByUser(input: IsFormSpaceStorageFileAccessibleByUserInput): Promise;