alepha
Version:
Alepha is a convention-driven TypeScript framework for building robust, end-to-end type-safe applications, from serverless APIs to full-stack React apps.
439 lines (438 loc) • 20.7 kB
TypeScript
import { BucketDescriptor } from "alepha/bucket";
import * as _alepha_core1 from "alepha";
import { Alepha, FileLike, Static } from "alepha";
import "alepha/server/security";
import * as _alepha_postgres16 from "alepha/postgres";
import { Page } from "alepha/postgres";
import * as _alepha_server0 from "alepha/server";
import { Ok } from "alepha/server";
import { DateTime, DateTimeProvider, DurationLike } from "alepha/datetime";
import * as _alepha_logger0 from "alepha/logger";
import { UserAccountToken } from "alepha/security";
import * as typebox25 from "typebox";
import * as dayjs2 from "dayjs";
//#region src/entities/files.d.ts
declare const files: _alepha_postgres16.EntityDescriptor<typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>>;
type FileEntity = Static<typeof files.schema>;
//#endregion
//#region src/schemas/fileQuerySchema.d.ts
declare const fileQuerySchema: typebox25.TObject<{
page: typebox25.TOptional<typebox25.TInteger>;
size: typebox25.TOptional<typebox25.TInteger>;
sort: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TOptional<typebox25.TString>;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
name: typebox25.TOptional<typebox25.TString>;
mimeType: typebox25.TOptional<typebox25.TString>;
creator: typebox25.TOptional<typebox25.TString>;
createdAfter: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
createdBefore: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
}>;
type FileQuery = Static<typeof fileQuerySchema>;
//#endregion
//#region src/schemas/fileResourceSchema.d.ts
declare const fileResourceSchema: typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>;
type FileResource = Static<typeof fileResourceSchema>;
//#endregion
//#region src/schemas/storageStatsSchema.d.ts
declare const bucketStatsSchema: typebox25.TObject<{
bucket: typebox25.TString;
totalSize: typebox25.TNumber;
fileCount: typebox25.TNumber;
}>;
declare const mimeTypeStatsSchema: typebox25.TObject<{
mimeType: typebox25.TString;
fileCount: typebox25.TNumber;
}>;
declare const storageStatsSchema: typebox25.TObject<{
totalSize: typebox25.TNumber;
totalFiles: typebox25.TNumber;
byBucket: typebox25.TArray<typebox25.TObject<{
bucket: typebox25.TString;
totalSize: typebox25.TNumber;
fileCount: typebox25.TNumber;
}>>;
byMimeType: typebox25.TArray<typebox25.TObject<{
mimeType: typebox25.TString;
fileCount: typebox25.TNumber;
}>>;
}>;
type BucketStats = Static<typeof bucketStatsSchema>;
type MimeTypeStats = Static<typeof mimeTypeStatsSchema>;
type StorageStats = Static<typeof storageStatsSchema>;
//#endregion
//#region src/services/FileService.d.ts
declare class FileService {
protected readonly alepha: Alepha;
protected readonly log: _alepha_logger0.Logger;
protected readonly fileRepository: _alepha_postgres16.RepositoryDescriptor<typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>>;
protected readonly dateTimeProvider: DateTimeProvider;
protected readonly defaultBucket: BucketDescriptor;
protected onUploadFile: _alepha_core1.HookDescriptor<"bucket:file:uploaded">;
protected onDeleteBucketFile: _alepha_core1.HookDescriptor<"bucket:file:deleted">;
/**
* Calculates SHA-256 checksum of a file.
*
* @param file - The file to calculate checksum for
* @returns Hexadecimal string representation of the SHA-256 hash
* @protected
*/
protected calculateChecksum(file: FileLike): Promise<string>;
/**
* Gets a bucket descriptor by name.
*
* @param bucketName - The name of the bucket to retrieve (defaults to "default")
* @returns The bucket descriptor
* @throws {NotFoundError} If the bucket is not found
*/
bucket(bucketName?: string): BucketDescriptor;
/**
* Finds files matching the given query criteria with pagination support.
* Supports filtering by bucket, tags, name, mimeType, creator, and date range.
*
* @param q - Query parameters including bucket, tags, name, mimeType, creator, date range, pagination, and sorting
* @returns Paginated list of file entities
*/
findFiles(q?: FileQuery): Promise<Page<FileEntity>>;
/**
* Finds files that have expired based on their expiration date.
* Limited to 1000 files per call to prevent memory issues.
*
* @returns Array of expired file entities
*/
findExpiredFiles(): Promise<FileEntity[]>;
/**
* Calculates an expiration date based on a TTL (time to live) duration.
*
* @param ttl - Duration like "1 day", "2 hours", etc.
* @returns DateTime representation of the expiration date, or undefined if no TTL provided
* @protected
*/
protected getExpirationDate(ttl?: DurationLike): DateTime | undefined;
/**
* Uploads a file to a bucket and creates a database record with metadata.
* Automatically calculates and stores the file checksum (SHA-256).
*
* @param file - The file to upload
* @param options - Upload options including bucket, expiration, user, and tags
* @param options.bucket - Target bucket name (defaults to "default")
* @param options.expirationDate - When the file should expire
* @param options.user - User performing the upload (for audit trail)
* @param options.tags - Tags to associate with the file
* @returns The created file entity with all metadata
* @throws {NotFoundError} If the specified bucket doesn't exist
*/
uploadFile(file: FileLike, options?: {
expirationDate?: string | DateTime;
bucket?: string;
user?: UserAccountToken;
tags?: string[];
}): Promise<FileEntity>;
/**
* Streams a file from storage by its database ID.
*
* @param id - The database ID (UUID) of the file to stream
* @returns The file object ready for streaming/downloading
* @throws {NotFoundError} If the file doesn't exist in the database
* @throws {FileNotFoundError} If the file exists in database but not in storage
*/
streamFile(id: string): Promise<FileLike>;
/**
* Updates file metadata (name, tags, expiration date).
* Does not modify the actual file content in storage.
*
* @param id - The database ID (UUID) of the file to update
* @param data - Partial file data to update
* @param data.name - New file name
* @param data.tags - New tags array
* @param data.expirationDate - New expiration date
* @returns The updated file entity
* @throws {NotFoundError} If the file doesn't exist in the database
*/
updateFile(id: string, data: {
name?: string;
tags?: string[];
expirationDate?: DateTime;
}): Promise<FileEntity>;
/**
* Deletes a file from both storage and database.
* Handles cases where file is already deleted from storage gracefully.
* Always ensures database record is removed even if storage deletion fails.
*
* @param id - The database ID (UUID) of the file to delete
* @returns Success response with the deleted file ID
* @throws {NotFoundError} If the file doesn't exist in the database
*/
deleteFile(id: string): Promise<Ok>;
/**
* Retrieves a file entity by its ID.
* If already an entity object, returns it as-is (convenience method).
*
* @param id - Either a UUID string or an existing FileEntity object
* @returns The file entity
* @throws {NotFoundError} If the file doesn't exist in the database
*/
getFileById(id: string | FileEntity): Promise<FileEntity>;
/**
* Gets storage statistics including total size, file count, and breakdowns by bucket and MIME type.
*
* @returns Storage statistics with aggregated data
*/
getStorageStats(): Promise<StorageStats>;
/**
* Converts a file entity to a file resource (API response format).
* Currently a pass-through, but allows for future transformation logic.
*
* @param entity - The file entity to convert
* @returns The file resource for API responses
*/
entityToResource(entity: FileEntity): FileResource;
}
//#endregion
//#region src/controllers/FileController.d.ts
/**
* REST API controller for file management operations.
* Provides endpoints for uploading, downloading, listing, and deleting files.
*/
declare class FileController {
protected readonly url = "/files";
protected readonly group = "files";
protected readonly fileService: FileService;
/**
* GET /files - Lists files with optional filtering and pagination.
* Supports filtering by bucket and tags.
*/
readonly findFiles: _alepha_server0.ActionDescriptorFn<{
query: typebox25.TObject<{
page: typebox25.TOptional<typebox25.TInteger>;
size: typebox25.TOptional<typebox25.TInteger>;
sort: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TOptional<typebox25.TString>;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
name: typebox25.TOptional<typebox25.TString>;
mimeType: typebox25.TOptional<typebox25.TString>;
creator: typebox25.TOptional<typebox25.TString>;
createdAfter: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
createdBefore: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
}>;
response: _alepha_postgres16.TPage<typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>>;
}>;
/**
* DELETE /files/:id - Deletes a file from both storage and database.
* Removes the file from the bucket and cleans up the database record.
*/
readonly deleteFile: _alepha_server0.ActionDescriptorFn<{
params: typebox25.TObject<{
id: typebox25.TString;
}>;
response: typebox25.TObject<{
ok: typebox25.TBoolean;
id: typebox25.TOptional<typebox25.TUnion<[typebox25.TString, typebox25.TInteger]>>;
count: typebox25.TOptional<typebox25.TNumber>;
}>;
}>;
/**
* POST /files - Uploads a new file to storage.
* Creates a database record with metadata and calculates checksum.
* Optionally specify bucket and expiration date.
*/
readonly uploadFile: _alepha_server0.ActionDescriptorFn<{
body: typebox25.TObject<{
file: _alepha_core1.TFile;
}>;
query: typebox25.TObject<{
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
bucket: typebox25.TOptional<typebox25.TString>;
}>;
response: typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>;
}>;
/**
* PATCH /files/:id - Updates file metadata.
* Allows updating name, tags, and expiration date without modifying file content.
*/
readonly updateFile: _alepha_server0.ActionDescriptorFn<{
params: typebox25.TObject<{
id: typebox25.TString;
}>;
body: typebox25.TObject<{
name: typebox25.TOptional<typebox25.TString>;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
}>;
response: typebox25.TObject<{
id: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TString, typeof _alepha_postgres16.PG_PRIMARY_KEY>, typeof _alepha_postgres16.PG_DEFAULT>;
version: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TInteger, typeof _alepha_postgres16.PG_VERSION>, typeof _alepha_postgres16.PG_DEFAULT>;
createdAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_CREATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
updatedAt: _alepha_postgres16.PgAttr<_alepha_postgres16.PgAttr<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>, typeof _alepha_postgres16.PG_UPDATED_AT>, typeof _alepha_postgres16.PG_DEFAULT>;
blobId: typebox25.TString;
creator: typebox25.TOptional<typebox25.TString>;
creatorRealm: typebox25.TOptional<typebox25.TString>;
creatorName: typebox25.TOptional<typebox25.TString>;
bucket: typebox25.TString;
expirationDate: typebox25.TOptional<typebox25.TCodec<typebox25.TString, dayjs2.Dayjs>>;
name: typebox25.TString;
size: typebox25.TNumber;
mimeType: typebox25.TString;
tags: typebox25.TOptional<typebox25.TArray<typebox25.TString>>;
checksum: typebox25.TOptional<typebox25.TString>;
}>;
}>;
/**
* GET /files/:id - Streams/downloads a file by its ID.
* Returns the file content with appropriate Content-Type header.
* Cached with ETag support for 1 year (immutable).
*/
readonly streamFile: _alepha_server0.ActionDescriptorFn<{
params: typebox25.TObject<{
id: typebox25.TString;
}>;
response: _alepha_core1.TFile;
}>;
}
//#endregion
//#region src/controllers/StorageStatsController.d.ts
/**
* REST API controller for storage analytics and statistics.
* Provides endpoints for viewing storage usage metrics.
*/
declare class StorageStatsController {
protected readonly url = "/files/stats";
protected readonly group = "files";
protected readonly fileService: FileService;
/**
* GET /files/stats - Gets storage statistics.
* Returns aggregated data including total size, file count,
* and breakdowns by bucket and MIME type.
*/
readonly getStats: _alepha_server0.ActionDescriptorFn<{
response: typebox25.TObject<{
totalSize: typebox25.TNumber;
totalFiles: typebox25.TNumber;
byBucket: typebox25.TArray<typebox25.TObject<{
bucket: typebox25.TString;
totalSize: typebox25.TNumber;
fileCount: typebox25.TNumber;
}>>;
byMimeType: typebox25.TArray<typebox25.TObject<{
mimeType: typebox25.TString;
fileCount: typebox25.TNumber;
}>>;
}>;
}>;
}
//#endregion
//#region src/index.d.ts
declare module "alepha/bucket" {
interface BucketFileOptions {
/**
* Time to live for the files in the bucket.
*/
ttl?: DurationLike;
/**
* Tags for the bucket.
*/
tags?: string[];
/**
* User performing the operation.
*/
user?: UserAccountToken;
/**
* Whether to persist the file metadata in the database.
*
* @default true
*/
persist?: boolean;
}
}
/**
* Provides file management API endpoints for Alepha applications.
*
* This module includes file upload, download, storage management,
* and file metadata operations.
*
* @module alepha.api.files
*/
declare const AlephaApiFiles: _alepha_core1.Service<_alepha_core1.Module<{}>>;
//#endregion
export { AlephaApiFiles, BucketStats, FileController, FileEntity, FileService, MimeTypeStats, StorageStats, StorageStatsController, bucketStatsSchema, files, mimeTypeStatsSchema, storageStatsSchema };
//# sourceMappingURL=index.d.ts.map