@cepseudo/assets 1.0.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +204 -0
  3. package/dist/assets_manager.d.ts +643 -0
  4. package/dist/assets_manager.d.ts.map +1 -0
  5. package/dist/assets_manager.js +1217 -0
  6. package/dist/assets_manager.js.map +1 -0
  7. package/dist/assets_openapi.d.ts +9 -0
  8. package/dist/assets_openapi.d.ts.map +1 -0
  9. package/dist/assets_openapi.js +391 -0
  10. package/dist/assets_openapi.js.map +1 -0
  11. package/dist/async_upload.d.ts +20 -0
  12. package/dist/async_upload.d.ts.map +1 -0
  13. package/dist/async_upload.js +10 -0
  14. package/dist/async_upload.js.map +1 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +17 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/map_manager.d.ts +61 -0
  20. package/dist/map_manager.d.ts.map +1 -0
  21. package/dist/map_manager.js +217 -0
  22. package/dist/map_manager.js.map +1 -0
  23. package/dist/presigned_upload_service.d.ts +52 -0
  24. package/dist/presigned_upload_service.d.ts.map +1 -0
  25. package/dist/presigned_upload_service.js +152 -0
  26. package/dist/presigned_upload_service.js.map +1 -0
  27. package/dist/tileset_manager.d.ts +128 -0
  28. package/dist/tileset_manager.d.ts.map +1 -0
  29. package/dist/tileset_manager.js +705 -0
  30. package/dist/tileset_manager.js.map +1 -0
  31. package/dist/upload_processor.d.ts +42 -0
  32. package/dist/upload_processor.d.ts.map +1 -0
  33. package/dist/upload_processor.js +138 -0
  34. package/dist/upload_processor.js.map +1 -0
  35. package/dist/upload_reconciler.d.ts +44 -0
  36. package/dist/upload_reconciler.d.ts.map +1 -0
  37. package/dist/upload_reconciler.js +140 -0
  38. package/dist/upload_reconciler.js.map +1 -0
  39. package/dist/utils/zip_utils.d.ts +66 -0
  40. package/dist/utils/zip_utils.d.ts.map +1 -0
  41. package/dist/utils/zip_utils.js +169 -0
  42. package/dist/utils/zip_utils.js.map +1 -0
  43. package/package.json +72 -0
@@ -0,0 +1,643 @@
1
+ import type { Component, Servable, AssetsManagerConfiguration, DataResponse, HttpMethod, OpenAPIDocumentable, OpenAPIComponentSpec, DataRecord, AuthResult, TypedRequest } from '@cepseudo/shared';
2
+ import type { StorageService } from '@cepseudo/storage';
3
+ import type { DatabaseAdapter, MetadataRow } from '@cepseudo/database';
4
+ import { AuthMiddleware, type HeadersLike } from '@cepseudo/auth';
5
+ import { PresignedUploadService } from './presigned_upload_service.js';
6
+ /**
7
+ * Extended metadata row for assets with additional fields.
8
+ * This will be stored as separate columns in the database table.
9
+ *
10
+ * @interface AssetMetadataRow
11
+ * @extends {MetadataRow}
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const assetMeta: AssetMetadataRow = {
16
+ * name: 'gltf',
17
+ * type: 'model/gltf-binary',
18
+ * url: '/storage/gltf/model.glb',
19
+ * date: new Date(),
20
+ * description: '3D building model',
21
+ * source: 'https://example.com/data-source',
22
+ * owner_id: 123,
23
+ * filename: 'building.glb',
24
+ * is_public: true
25
+ * }
26
+ * ```
27
+ */
28
+ export interface AssetMetadataRow extends MetadataRow {
29
+ /** Human-readable description of the asset */
30
+ description: string;
31
+ /** Source URL for data provenance and licensing compliance (must be valid URL) */
32
+ source: string;
33
+ /** ID of the user who owns this asset (for access control) */
34
+ owner_id: number | null;
35
+ /** Original filename provided by the user */
36
+ filename: string;
37
+ /** Whether the asset is publicly accessible (true) or private (false) */
38
+ is_public: boolean;
39
+ }
40
+ /**
41
+ * Request payload for creating a new asset.
42
+ *
43
+ * @interface CreateAssetRequest
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const request: CreateAssetRequest = {
48
+ * description: '3D model of building',
49
+ * source: 'https://city-data.example.com/buildings',
50
+ * owner_id: 'user123',
51
+ * filename: 'building.glb',
52
+ * file: fileBuffer,
53
+ * is_public: true
54
+ * }
55
+ * ```
56
+ */
57
+ export interface CreateAssetRequest {
58
+ /** Human-readable description of the asset */
59
+ description: string;
60
+ /** Source URL for data provenance (validated as proper URL) */
61
+ source: string;
62
+ /** Owner user ID for access control (can be null) */
63
+ owner_id: number | null;
64
+ /** Original filename */
65
+ filename: string;
66
+ /** File content as Buffer */
67
+ file: Buffer;
68
+ /** Whether the asset is publicly accessible (default: true) */
69
+ is_public?: boolean;
70
+ }
71
+ /**
72
+ * Request payload for updating asset metadata.
73
+ *
74
+ * @interface UpdateAssetRequest
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const updates: UpdateAssetRequest = {
79
+ * description: 'Updated building model with new textures',
80
+ * source: 'https://updated-source.example.com',
81
+ * is_public: false
82
+ * }
83
+ * ```
84
+ */
85
+ export interface UpdateAssetRequest {
86
+ /** Updated description (optional) */
87
+ description?: string;
88
+ /** Updated source URL (optional, validated if provided) */
89
+ source?: string;
90
+ /** Updated visibility (optional) */
91
+ is_public?: boolean;
92
+ }
93
+ /**
94
+ * Abstract base class for Assets Manager components with authentication and access control.
95
+ *
96
+ * Provides secure file upload, storage, and retrieval capabilities following the Digital Twin framework patterns.
97
+ * Each concrete implementation manages a specific type of asset and creates its own database table.
98
+ *
99
+ * ## Authentication & Authorization
100
+ *
101
+ * - **Write Operations** (POST, PUT, DELETE): Require authentication via Apache APISIX headers
102
+ * - **User Management**: Automatically creates/updates user records from Keycloak data
103
+ * - **Access Control**: Users can only modify/delete their own assets (ownership-based)
104
+ * - **Resource Linking**: Assets are automatically linked to their owners via user_id foreign key
105
+ *
106
+ * ## Required Headers for Authenticated Endpoints
107
+ *
108
+ * - `x-user-id`: Keycloak user UUID (required)
109
+ * - `x-user-roles`: Comma-separated list of user roles (optional)
110
+ *
111
+ * These headers are automatically added by Apache APISIX after successful Keycloak authentication.
112
+ *
113
+ * @abstract
114
+ * @class AssetsManager
115
+ * @implements {Component}
116
+ * @implements {Servable}
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Create concrete implementations for different asset types
121
+ * class GLTFAssetsManager extends AssetsManager {
122
+ * getConfiguration() {
123
+ * return { name: 'gltf', description: 'GLTF 3D models manager', ... }
124
+ * }
125
+ * }
126
+ *
127
+ * class PointCloudAssetsManager extends AssetsManager {
128
+ * getConfiguration() {
129
+ * return { name: 'pointcloud', description: 'Point cloud data manager', ... }
130
+ * }
131
+ * }
132
+ *
133
+ * // Usage in engine
134
+ * const gltfManager = new GLTFAssetsManager()
135
+ * gltfManager.setDependencies(database, storage)
136
+ *
137
+ * // Each creates its own table and endpoints:
138
+ * // - GLTFAssetsManager → table 'gltf', endpoints /gltf/*
139
+ * // - PointCloudAssetsManager → table 'pointcloud', endpoints /pointcloud/*
140
+ * ```
141
+ *
142
+ * @remarks
143
+ * Asset metadata is stored as dedicated columns in the database table:
144
+ * - id, name, url, date (standard columns)
145
+ * - description, source, owner_id, filename (asset-specific columns)
146
+ *
147
+ * Each concrete AssetsManager creates its own table based on the configuration name.
148
+ */
149
+ export declare abstract class AssetsManager implements Component, Servable, OpenAPIDocumentable {
150
+ protected db: DatabaseAdapter;
151
+ protected storage: StorageService;
152
+ protected authMiddleware: AuthMiddleware;
153
+ protected presignedService: PresignedUploadService;
154
+ /**
155
+ * Injects dependencies into the assets manager.
156
+ *
157
+ * Called by the framework during component initialization.
158
+ *
159
+ * @param {DatabaseAdapter} db - The database adapter for metadata storage
160
+ * @param {StorageService} storage - The storage service for file persistence
161
+ * @param {AuthMiddleware} [authMiddleware] - Optional auth middleware for authentication (created automatically if not provided)
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * // Standard usage (AuthMiddleware created automatically)
166
+ * const assetsManager = new MyAssetsManager()
167
+ * assetsManager.setDependencies(databaseAdapter, storageService)
168
+ *
169
+ * // For testing (inject mock AuthMiddleware)
170
+ * assetsManager.setDependencies(databaseAdapter, storageService, mockAuthMiddleware)
171
+ * ```
172
+ */
173
+ setDependencies(db: DatabaseAdapter, storage: StorageService, authMiddleware?: AuthMiddleware): void;
174
+ /**
175
+ * Returns the configuration of the assets manager.
176
+ *
177
+ * Must be implemented by subclasses to define the asset type,
178
+ * table name, and content types.
179
+ *
180
+ * @abstract
181
+ * @returns {ComponentConfiguration} The component configuration
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * class GLTFAssetsManager extends AssetsManager {
186
+ * getConfiguration(): ComponentConfiguration {
187
+ * return {
188
+ * name: 'gltf',
189
+ * description: 'GLTF 3D models manager',
190
+ * contentType: 'model/gltf-binary',
191
+ * tags: ['assets', '3d', 'gltf']
192
+ * }
193
+ * }
194
+ * }
195
+ * ```
196
+ */
197
+ abstract getConfiguration(): AssetsManagerConfiguration;
198
+ /**
199
+ * Validates that a source string is a valid URL.
200
+ *
201
+ * Used internally to ensure data provenance URLs are properly formatted.
202
+ *
203
+ * @private
204
+ * @param {string} source - The source URL to validate
205
+ * @returns {boolean} True if the source is a valid URL, false otherwise
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * this.validateSourceURL('https://example.com/data') // returns true
210
+ * this.validateSourceURL('not-a-url') // returns false
211
+ * ```
212
+ */
213
+ private validateSourceURL;
214
+ /**
215
+ * Validates that a filename has the correct extension as configured.
216
+ *
217
+ * Used internally to ensure uploaded files match the expected extension.
218
+ *
219
+ * @private
220
+ * @param {string} filename - The filename to validate
221
+ * @returns {boolean} True if the filename has the correct extension or no extension is configured, false otherwise
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * // If config.extension = '.glb'
226
+ * this.validateFileExtension('model.glb') // returns true
227
+ * this.validateFileExtension('model.json') // returns false
228
+ * this.validateFileExtension('model') // returns false
229
+ *
230
+ * // If config.extension is undefined
231
+ * this.validateFileExtension('any-file.ext') // returns true
232
+ * ```
233
+ */
234
+ protected validateFileExtension(filename: string): boolean;
235
+ /**
236
+ * Validates that a string is valid base64-encoded data.
237
+ *
238
+ * Used internally to ensure file data in batch uploads is properly base64-encoded
239
+ * before attempting to decode it.
240
+ *
241
+ * @private
242
+ * @param {any} data - Data to validate as base64
243
+ * @returns {boolean} True if data is a valid base64 string, false otherwise
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * this.validateBase64('SGVsbG8gV29ybGQ=') // returns true
248
+ * this.validateBase64('not-base64!@#') // returns false
249
+ * this.validateBase64(123) // returns false (not a string)
250
+ * this.validateBase64('') // returns false (empty string)
251
+ * ```
252
+ */
253
+ private validateBase64;
254
+ /**
255
+ * Authenticates a request and returns the user record.
256
+ *
257
+ * This method consolidates the authentication flow:
258
+ * 1. Validates APISIX headers are present
259
+ * 2. Parses authentication headers
260
+ * 3. Finds or creates user record in database
261
+ *
262
+ * @param req - HTTP request object
263
+ * @returns AuthResult with either userRecord on success or DataResponse on failure
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * const authResult = await this.authenticateRequest(req)
268
+ * if (!authResult.success) {
269
+ * return authResult.response
270
+ * }
271
+ * const userRecord = authResult.userRecord
272
+ * ```
273
+ */
274
+ protected authenticateRequest(req: TypedRequest): Promise<AuthResult>;
275
+ /**
276
+ * Extracts upload data from multipart form request.
277
+ *
278
+ * @param req - HTTP request object with body and file
279
+ * @returns UploadData object with extracted fields
280
+ */
281
+ private extractUploadData;
282
+ /**
283
+ * Validates required fields for asset upload and returns validated data.
284
+ *
285
+ * @param data - Upload data to validate
286
+ * @returns UploadValidationResult with validated data on success or error response on failure
287
+ */
288
+ private validateUploadFields;
289
+ /**
290
+ * Reads file content from temporary upload path.
291
+ *
292
+ * @param filePath - Path to temporary file
293
+ * @returns Buffer with file content
294
+ * @throws Error if file cannot be read
295
+ */
296
+ private readTempFile;
297
+ /**
298
+ * Cleans up temporary file after processing.
299
+ * Logs cleanup errors but doesn't throw.
300
+ *
301
+ * @param filePath - Path to temporary file
302
+ */
303
+ private cleanupTempFile;
304
+ /**
305
+ * Validates ownership of an asset.
306
+ *
307
+ * Admins can modify any asset. Regular users can only modify their own assets
308
+ * or assets with no owner (owner_id = null).
309
+ *
310
+ * @param asset - Asset record to check
311
+ * @param userId - User ID to validate against
312
+ * @param headers - HTTP request headers (optional, for admin check)
313
+ * @returns DataResponse with error if not owner/admin, undefined if valid
314
+ */
315
+ protected validateOwnership(asset: DataRecord, userId: number, headers?: HeadersLike): DataResponse | undefined;
316
+ /**
317
+ * Checks if a user can access a private asset.
318
+ *
319
+ * @param asset - Asset record to check
320
+ * @param req - HTTP request for authentication context
321
+ * @returns DataResponse with error if access denied, undefined if allowed
322
+ */
323
+ private checkPrivateAssetAccess;
324
+ /**
325
+ * Fetches an asset by ID with full access control validation.
326
+ *
327
+ * This method consolidates the common logic for retrieving an asset:
328
+ * 1. Validates that ID is provided
329
+ * 2. Fetches the asset from database
330
+ * 3. Verifies the asset belongs to this component
331
+ * 4. Checks access permissions for private assets
332
+ *
333
+ * @param req - HTTP request with params.id
334
+ * @returns Object with asset on success, or DataResponse on failure
335
+ */
336
+ private fetchAssetWithAccessCheck;
337
+ /**
338
+ * Upload a new asset file with metadata.
339
+ *
340
+ * Stores the file using the storage service and saves metadata to the database.
341
+ * Asset metadata is stored as dedicated columns in the database table.
342
+ *
343
+ * @param {CreateAssetRequest} request - The asset upload request
344
+ * @throws {Error} If source URL is invalid
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * await assetsManager.uploadAsset({
349
+ * description: '3D building model',
350
+ * source: 'https://city-data.example.com/buildings',
351
+ * owner_id: 'user123',
352
+ * filename: 'building.glb',
353
+ * file: fileBuffer,
354
+ * is_public: true
355
+ * })
356
+ * ```
357
+ */
358
+ uploadAsset(request: CreateAssetRequest): Promise<void>;
359
+ /**
360
+ * Retrieve all assets for this component (like other components).
361
+ *
362
+ * Returns a JSON list of all assets with their metadata, following the
363
+ * framework pattern but adapted for assets management.
364
+ *
365
+ * Access control:
366
+ * - Unauthenticated users: Can only see public assets
367
+ * - Authenticated users: Can see public assets + their own private assets
368
+ * - Admin users: Can see all assets (public and private from all users)
369
+ *
370
+ * @returns {Promise<DataResponse>} JSON response with all assets
371
+ */
372
+ retrieve(req?: TypedRequest): Promise<DataResponse>;
373
+ /**
374
+ * Gets the authenticated user's database ID from request headers.
375
+ *
376
+ * @param req - HTTP request object
377
+ * @returns User ID or null if not authenticated
378
+ */
379
+ private getAuthenticatedUserId;
380
+ /**
381
+ * Formats assets for API response with metadata and URLs.
382
+ *
383
+ * @param assets - Array of asset records
384
+ * @returns Formatted assets array ready for JSON serialization
385
+ */
386
+ private formatAssetsForResponse;
387
+ /**
388
+ * Get all assets for this component type.
389
+ *
390
+ * Retrieves all assets managed by this component, with their metadata.
391
+ * Uses a very old start date to get all records.
392
+ *
393
+ * @returns {Promise<DataRecord[]>} Array of all asset records
394
+ *
395
+ * @example
396
+ * ```typescript
397
+ * const allAssets = await assetsManager.getAllAssets()
398
+ * // Returns: [{ id, name, type, url, date, contentType }, ...]
399
+ * ```
400
+ */
401
+ getAllAssets(): Promise<DataRecord[]>;
402
+ /**
403
+ * Get asset by specific ID.
404
+ *
405
+ * @param {string} id - The asset ID to retrieve
406
+ * @returns {Promise<DataRecord | undefined>} The asset record or undefined if not found
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * const asset = await assetsManager.getAssetById('123')
411
+ * if (asset) {
412
+ * const fileData = await asset.data()
413
+ * }
414
+ * ```
415
+ */
416
+ getAssetById(id: string): Promise<DataRecord | undefined>;
417
+ /**
418
+ * Update asset metadata by ID.
419
+ *
420
+ * Updates the metadata (description, source, and/or visibility) of a specific asset.
421
+ * Asset metadata is stored as dedicated columns in the database.
422
+ *
423
+ * @param {string} id - The ID of the asset to update
424
+ * @param {UpdateAssetRequest} updates - The metadata updates to apply
425
+ * @throws {Error} If source URL is invalid or asset not found
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * await assetsManager.updateAssetMetadata('123', {
430
+ * description: 'Updated building model with new textures',
431
+ * source: 'https://updated-source.example.com',
432
+ * is_public: false
433
+ * })
434
+ * ```
435
+ */
436
+ updateAssetMetadata(id: string, updates: UpdateAssetRequest): Promise<void>;
437
+ /**
438
+ * Delete asset by ID.
439
+ *
440
+ * Removes a specific asset.
441
+ *
442
+ * @param {string} id - The ID of the asset to delete
443
+ * @throws {Error} If asset not found or doesn't belong to this component
444
+ *
445
+ * @example
446
+ * ```typescript
447
+ * await assetsManager.deleteAssetById('123')
448
+ * ```
449
+ */
450
+ deleteAssetById(id: string): Promise<void>;
451
+ /**
452
+ * Delete latest asset (simplified)
453
+ *
454
+ * Removes the most recently uploaded asset for this component type.
455
+ *
456
+ * @throws {Error} If no assets exist to delete
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * await assetsManager.deleteLatestAsset()
461
+ * ```
462
+ */
463
+ deleteLatestAsset(): Promise<void>;
464
+ /**
465
+ * Upload multiple assets in batch for better performance
466
+ *
467
+ * @param {CreateAssetRequest[]} requests - Array of asset upload requests
468
+ * @throws {Error} If any source URL is invalid
469
+ *
470
+ * @example
471
+ * ```typescript
472
+ * await assetsManager.uploadAssetsBatch([
473
+ * { description: 'Model 1', source: 'https://example.com/1', file: buffer1, ... },
474
+ * { description: 'Model 2', source: 'https://example.com/2', file: buffer2, ... }
475
+ * ])
476
+ * ```
477
+ */
478
+ uploadAssetsBatch(requests: CreateAssetRequest[]): Promise<void>;
479
+ /**
480
+ * Delete multiple assets by IDs in batch
481
+ *
482
+ * @param {string[]} ids - Array of asset IDs to delete
483
+ * @throws {Error} If any asset not found or doesn't belong to this component
484
+ */
485
+ deleteAssetsBatch(ids: string[]): Promise<void>;
486
+ /**
487
+ * Get endpoints following the framework pattern
488
+ */
489
+ /**
490
+ * Get HTTP endpoints exposed by this assets manager.
491
+ *
492
+ * Returns the standard CRUD endpoints following the framework pattern.
493
+ *
494
+ * @returns {Array} Array of endpoint descriptors with methods, paths, and handlers
495
+ *
496
+ * @example
497
+ * ```typescript
498
+ * // For a manager with assetType: 'gltf', provides:
499
+ * GET /gltf - Get all assets
500
+ * POST /gltf/upload - Upload new asset
501
+ * GET /gltf/123 - Get specific asset
502
+ * PUT /gltf/123 - Update asset metadata
503
+ * GET /gltf/123/download - Download asset
504
+ * DELETE /gltf/123 - Delete asset
505
+ * ```
506
+ */
507
+ getEndpoints(): Array<{
508
+ method: HttpMethod;
509
+ path: string;
510
+ handler: (req: TypedRequest) => Promise<DataResponse>;
511
+ responseType?: string;
512
+ }>;
513
+ /**
514
+ * Returns the OpenAPI specification for this assets manager's endpoints.
515
+ *
516
+ * Generates documentation for all CRUD endpoints including batch operations.
517
+ * Can be overridden by subclasses for more detailed specifications.
518
+ *
519
+ * @returns {OpenAPIComponentSpec} OpenAPI paths, tags, and schemas for this assets manager
520
+ */
521
+ getOpenAPISpec(): OpenAPIComponentSpec;
522
+ /**
523
+ * Handle presigned upload URL request.
524
+ * Delegates to PresignedUploadService.
525
+ */
526
+ handlePresignedUploadRequest(req: TypedRequest): Promise<DataResponse>;
527
+ /**
528
+ * Handle presigned upload confirmation.
529
+ * Delegates to PresignedUploadService.
530
+ */
531
+ handleUploadConfirm(req: TypedRequest): Promise<DataResponse>;
532
+ /**
533
+ * Handle single asset upload via HTTP POST (multipart/form-data).
534
+ */
535
+ handleUpload(req: TypedRequest): Promise<DataResponse>;
536
+ /**
537
+ * Handle update endpoint (PUT).
538
+ *
539
+ * Updates metadata for a specific asset by ID.
540
+ *
541
+ * @param {any} req - HTTP request object with params.id and body containing updates
542
+ * @returns {Promise<DataResponse>} HTTP response
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * // PUT /gltf/123
547
+ * // Body: { "description": "Updated model", "source": "https://new-source.com" }
548
+ * ```
549
+ */
550
+ handleUpdate(req: TypedRequest): Promise<DataResponse>;
551
+ /**
552
+ * Handle get asset endpoint (GET).
553
+ *
554
+ * Returns the file content of a specific asset by ID for display/use in front-end.
555
+ * No download headers - just the raw file content.
556
+ *
557
+ * Access control:
558
+ * - Public assets: Accessible to everyone
559
+ * - Private assets: Accessible only to owner
560
+ * - Admin users: Can access all assets (public and private)
561
+ *
562
+ * @param {any} req - HTTP request object with params.id
563
+ * @returns {Promise<DataResponse>} HTTP response with file content
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * // GET /gltf/123
568
+ * // Returns the .glb file content for display in 3D viewer
569
+ * ```
570
+ */
571
+ handleGetAsset(req: TypedRequest): Promise<DataResponse>;
572
+ /**
573
+ * Handle download endpoint (GET).
574
+ *
575
+ * Downloads the file content of a specific asset by ID with download headers.
576
+ * Forces browser to download the file rather than display it.
577
+ *
578
+ * Access control:
579
+ * - Public assets: Accessible to everyone
580
+ * - Private assets: Accessible only to owner
581
+ * - Admin users: Can download all assets (public and private)
582
+ *
583
+ * @param {any} req - HTTP request object with params.id
584
+ * @returns {Promise<DataResponse>} HTTP response with file content and download headers
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * // GET /gltf/123/download
589
+ * // Returns the .glb file with download headers - browser will save it
590
+ * ```
591
+ */
592
+ handleDownload(req: TypedRequest): Promise<DataResponse>;
593
+ /**
594
+ * Handle delete endpoint (DELETE).
595
+ *
596
+ * Deletes a specific asset by ID.
597
+ *
598
+ * @param {any} req - HTTP request object with params.id
599
+ * @returns {Promise<DataResponse>} HTTP response
600
+ *
601
+ * @example
602
+ * ```typescript
603
+ * // DELETE /gltf/123
604
+ * ```
605
+ */
606
+ handleDelete(req: TypedRequest): Promise<DataResponse>;
607
+ /**
608
+ * Handle batch upload endpoint
609
+ */
610
+ handleUploadBatch(req: TypedRequest): Promise<DataResponse>;
611
+ /**
612
+ * Validates all requests in a batch upload.
613
+ *
614
+ * @param requests - Array of upload requests to validate
615
+ * @returns DataResponse with error if validation fails, undefined if valid
616
+ */
617
+ private validateBatchRequests;
618
+ /**
619
+ * Processes batch upload requests.
620
+ *
621
+ * @param requests - Array of upload requests
622
+ * @param ownerId - Owner user ID
623
+ * @returns Array of results for each upload
624
+ */
625
+ private processBatchUploads;
626
+ /**
627
+ * Handle batch delete endpoint
628
+ */
629
+ handleDeleteBatch(req: TypedRequest): Promise<DataResponse>;
630
+ /**
631
+ * Processes batch delete requests.
632
+ *
633
+ * Admins can delete any asset. Regular users can only delete their own assets
634
+ * or assets with no owner.
635
+ *
636
+ * @param ids - Array of asset IDs to delete
637
+ * @param userId - User ID for ownership validation
638
+ * @param headers - HTTP request headers (for admin check)
639
+ * @returns Array of results for each deletion
640
+ */
641
+ private processBatchDeletes;
642
+ }
643
+ //# sourceMappingURL=assets_manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets_manager.d.ts","sourceRoot":"","sources":["../src/assets_manager.ts"],"names":[],"mappings":"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"}