digitaltwin-core
Version:
Minimalist framework to collect and handle data in a Digital Twin project
414 lines • 13.5 kB
TypeScript
import type { Component, Servable } from './interfaces.js';
import type { ComponentConfiguration, DataResponse } from './types.js';
import type { HttpMethod } from '../engine/endpoints.js';
import type { StorageService } from '../storage/storage_service.js';
import type { DatabaseAdapter, MetadataRow } from '../database/database_adapter.js';
import type { DataRecord } from '../types/data_record.js';
/**
* Extended metadata row for assets with additional fields.
* This will be stored as separate columns in the database table.
*
* @interface AssetMetadataRow
* @extends {MetadataRow}
*
* @example
* ```typescript
* const assetMeta: AssetMetadataRow = {
* name: 'gltf',
* type: 'model/gltf-binary',
* url: '/storage/gltf/model.glb',
* date: new Date(),
* description: '3D building model',
* source: 'https://example.com/data-source',
* owner_id: 'user123',
* filename: 'building.glb'
* }
* ```
*/
export interface AssetMetadataRow extends MetadataRow {
/** Human-readable description of the asset */
description: string;
/** Source URL for data provenance and licensing compliance (must be valid URL) */
source: string;
/** ID of the user who owns this asset (for access control) */
owner_id: string | null;
/** Original filename provided by the user */
filename: string;
}
/**
* Request payload for creating a new asset.
*
* @interface CreateAssetRequest
*
* @example
* ```typescript
* const request: CreateAssetRequest = {
* description: '3D model of building',
* source: 'https://city-data.example.com/buildings',
* owner_id: 'user123',
* filename: 'building.glb',
* file: fileBuffer
* }
* ```
*/
export interface CreateAssetRequest {
/** Human-readable description of the asset */
description: string;
/** Source URL for data provenance (validated as proper URL) */
source: string;
/** Owner user ID for access control (can be null) */
owner_id: string | null;
/** Original filename */
filename: string;
/** File content as Buffer */
file: Buffer;
}
/**
* Request payload for updating asset metadata.
*
* @interface UpdateAssetRequest
*
* @example
* ```typescript
* const updates: UpdateAssetRequest = {
* description: 'Updated building model with new textures',
* source: 'https://updated-source.example.com'
* }
* ```
*/
export interface UpdateAssetRequest {
/** Updated description (optional) */
description?: string;
/** Updated source URL (optional, validated if provided) */
source?: string;
}
/**
* Abstract base class for Assets Manager components.
*
* Provides file upload, storage, and retrieval capabilities following the Digital Twin framework patterns.
* Each concrete implementation manages a specific type of asset and creates its own database table.
*
* @abstract
* @class AssetsManager
* @implements {Component}
* @implements {Servable}
*
* @example
* ```typescript
* // Create concrete implementations for different asset types
* class GLTFAssetsManager extends AssetsManager {
* getConfiguration() {
* return { name: 'gltf', description: 'GLTF 3D models manager', ... }
* }
* }
*
* class PointCloudAssetsManager extends AssetsManager {
* getConfiguration() {
* return { name: 'pointcloud', description: 'Point cloud data manager', ... }
* }
* }
*
* // Usage in engine
* const gltfManager = new GLTFAssetsManager()
* gltfManager.setDependencies(database, storage)
*
* // Each creates its own table and endpoints:
* // - GLTFAssetsManager → table 'gltf', endpoints /gltf/*
* // - PointCloudAssetsManager → table 'pointcloud', endpoints /pointcloud/*
* ```
*
* @remarks
* Asset metadata is stored as dedicated columns in the database table:
* - id, name, url, date (standard columns)
* - description, source, owner_id, filename (asset-specific columns)
*
* Each concrete AssetsManager creates its own table based on the configuration name.
*/
export declare abstract class AssetsManager implements Component, Servable {
protected db: DatabaseAdapter;
protected storage: StorageService;
/**
* Injects dependencies into the assets manager.
*
* Called by the framework during component initialization.
*
* @param {DatabaseAdapter} db - The database adapter for metadata storage
* @param {StorageService} storage - The storage service for file persistence
*
* @example
* ```typescript
* const assetsManager = new MyAssetsManager()
* assetsManager.setDependencies(databaseAdapter, storageService)
* ```
*/
setDependencies(db: DatabaseAdapter, storage: StorageService): void;
/**
* Returns the configuration of the assets manager.
*
* Must be implemented by subclasses to define the asset type,
* table name, and content types.
*
* @abstract
* @returns {ComponentConfiguration} The component configuration
*
* @example
* ```typescript
* class GLTFAssetsManager extends AssetsManager {
* getConfiguration(): ComponentConfiguration {
* return {
* name: 'gltf',
* description: 'GLTF 3D models manager',
* contentType: 'model/gltf-binary',
* tags: ['assets', '3d', 'gltf']
* }
* }
* }
* ```
*/
abstract getConfiguration(): ComponentConfiguration;
/**
* Validates that a source string is a valid URL.
*
* Used internally to ensure data provenance URLs are properly formatted.
*
* @private
* @param {string} source - The source URL to validate
* @returns {boolean} True if the source is a valid URL, false otherwise
*
* @example
* ```typescript
* this.validateSourceURL('https://example.com/data') // returns true
* this.validateSourceURL('not-a-url') // returns false
* ```
*/
private validateSourceURL;
/**
* Upload a new asset file with metadata.
*
* Stores the file using the storage service and saves metadata to the database.
* Asset metadata is stored as dedicated columns in the database table.
*
* @param {CreateAssetRequest} request - The asset upload request
* @throws {Error} If source URL is invalid
*
* @example
* ```typescript
* await assetsManager.uploadAsset({
* description: '3D building model',
* source: 'https://city-data.example.com/buildings',
* owner_id: 'user123',
* filename: 'building.glb',
* file: fileBuffer
* })
* ```
*/
uploadAsset(request: CreateAssetRequest): Promise<void>;
/**
* Retrieve all assets for this component (like other components).
*
* Returns a JSON list of all assets with their metadata, following the
* framework pattern but adapted for assets management.
*
* @returns {Promise<DataResponse>} JSON response with all assets
*/
retrieve(): Promise<DataResponse>;
/**
* Get all assets for this component type.
*
* Retrieves all assets managed by this component, with their metadata.
* Uses a very old start date to get all records.
*
* @returns {Promise<DataRecord[]>} Array of all asset records
*
* @example
* ```typescript
* const allAssets = await assetsManager.getAllAssets()
* // Returns: [{ id, name, type, url, date, contentType }, ...]
* ```
*/
getAllAssets(): Promise<DataRecord[]>;
/**
* Get asset by specific ID.
*
* @param {string} id - The asset ID to retrieve
* @returns {Promise<DataRecord | undefined>} The asset record or undefined if not found
*
* @example
* ```typescript
* const asset = await assetsManager.getAssetById('123')
* if (asset) {
* const fileData = await asset.data()
* }
* ```
*/
getAssetById(id: string): Promise<DataRecord | undefined>;
/**
* Update asset metadata by ID.
*
* Updates the metadata (description and/or source) of a specific asset.
* Asset metadata is stored as dedicated columns in the database.
*
* @param {string} id - The ID of the asset to update
* @param {UpdateAssetRequest} updates - The metadata updates to apply
* @throws {Error} If source URL is invalid or asset not found
*
* @example
* ```typescript
* await assetsManager.updateAssetMetadata('123', {
* description: 'Updated building model with new textures',
* source: 'https://updated-source.example.com'
* })
* ```
*/
updateAssetMetadata(id: string, updates: UpdateAssetRequest): Promise<void>;
/**
* Delete asset by ID.
*
* Removes a specific asset.
*
* @param {string} id - The ID of the asset to delete
* @throws {Error} If asset not found or doesn't belong to this component
*
* @example
* ```typescript
* await assetsManager.deleteAssetById('123')
* ```
*/
deleteAssetById(id: string): Promise<void>;
/**
* Delete latest asset (simplified)
*
* Removes the most recently uploaded asset for this component type.
*
* @throws {Error} If no assets exist to delete
*
* @example
* ```typescript
* await assetsManager.deleteLatestAsset()
* ```
*/
deleteLatestAsset(): Promise<void>;
/**
* Upload multiple assets in batch for better performance
*
* @param {CreateAssetRequest[]} requests - Array of asset upload requests
* @throws {Error} If any source URL is invalid
*
* @example
* ```typescript
* await assetsManager.uploadAssetsBatch([
* { description: 'Model 1', source: 'https://example.com/1', file: buffer1, ... },
* { description: 'Model 2', source: 'https://example.com/2', file: buffer2, ... }
* ])
* ```
*/
uploadAssetsBatch(requests: CreateAssetRequest[]): Promise<void>;
/**
* Delete multiple assets by IDs in batch
*
* @param {string[]} ids - Array of asset IDs to delete
* @throws {Error} If any asset not found or doesn't belong to this component
*/
deleteAssetsBatch(ids: string[]): Promise<void>;
/**
* Get endpoints following the framework pattern
*/
/**
* Get HTTP endpoints exposed by this assets manager.
*
* Returns the standard CRUD endpoints following the framework pattern.
*
* @returns {Array} Array of endpoint descriptors with methods, paths, and handlers
*
* @example
* ```typescript
* // For a manager with assetType: 'gltf', provides:
* GET /gltf - Get all assets
* POST /gltf/upload - Upload new asset
* GET /gltf/123 - Get specific asset
* PUT /gltf/123 - Update asset metadata
* GET /gltf/123/download - Download asset
* DELETE /gltf/123 - Delete asset
* ```
*/
getEndpoints(): Array<{
method: HttpMethod;
path: string;
handler: (...args: any[]) => any;
responseType?: string;
}>;
/**
* Handle upload endpoint
*/
handleUpload(req: any): Promise<DataResponse>;
/**
* Handle update endpoint (PUT).
*
* Updates metadata for a specific asset by ID.
*
* @param {any} req - HTTP request object with params.id and body containing updates
* @returns {Promise<DataResponse>} HTTP response
*
* @example
* ```typescript
* // PUT /gltf/123
* // Body: { "description": "Updated model", "source": "https://new-source.com" }
* ```
*/
handleUpdate(req: any): Promise<DataResponse>;
/**
* Handle get asset endpoint (GET).
*
* Returns the file content of a specific asset by ID for display/use in front-end.
* No download headers - just the raw file content.
*
* @param {any} req - HTTP request object with params.id
* @returns {Promise<DataResponse>} HTTP response with file content
*
* @example
* ```typescript
* // GET /gltf/123
* // Returns the .glb file content for display in 3D viewer
* ```
*/
handleGetAsset(req: any): Promise<DataResponse>;
/**
* Handle download endpoint (GET).
*
* Downloads the file content of a specific asset by ID with download headers.
* Forces browser to download the file rather than display it.
*
* @param {any} req - HTTP request object with params.id
* @returns {Promise<DataResponse>} HTTP response with file content and download headers
*
* @example
* ```typescript
* // GET /gltf/123/download
* // Returns the .glb file with download headers - browser will save it
* ```
*/
handleDownload(req: any): Promise<DataResponse>;
/**
* Handle delete endpoint (DELETE).
*
* Deletes a specific asset by ID.
*
* @param {any} req - HTTP request object with params.id
* @returns {Promise<DataResponse>} HTTP response
*
* @example
* ```typescript
* // DELETE /gltf/123
* ```
*/
handleDelete(req: any): Promise<DataResponse>;
/**
* Handle batch upload endpoint
*/
handleUploadBatch(req: any): Promise<DataResponse>;
/**
* Handle batch delete endpoint
*/
handleDeleteBatch(req: any): Promise<DataResponse>;
}
//# sourceMappingURL=assets_manager.d.ts.map