digitaltwin-core 0.14.2 → 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.
- package/LICENSE +20 -20
- package/README.md +494 -359
- package/dist/auth/apisix_parser.d.ts +141 -0
- package/dist/auth/apisix_parser.d.ts.map +1 -0
- package/dist/auth/apisix_parser.js +161 -0
- package/dist/auth/apisix_parser.js.map +1 -0
- package/dist/auth/auth_config.d.ts +126 -0
- package/dist/auth/auth_config.d.ts.map +1 -0
- package/dist/auth/auth_config.js +169 -0
- package/dist/auth/auth_config.js.map +1 -0
- package/dist/auth/auth_provider.d.ts +118 -0
- package/dist/auth/auth_provider.d.ts.map +1 -0
- package/dist/auth/auth_provider.js +8 -0
- package/dist/auth/auth_provider.js.map +1 -0
- package/dist/auth/auth_provider_factory.d.ts +91 -0
- package/dist/auth/auth_provider_factory.d.ts.map +1 -0
- package/dist/auth/auth_provider_factory.js +146 -0
- package/dist/auth/auth_provider_factory.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts +78 -0
- package/dist/auth/providers/gateway_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/gateway_auth_provider.js +109 -0
- package/dist/auth/providers/gateway_auth_provider.js.map +1 -0
- package/dist/auth/providers/index.d.ts +4 -0
- package/dist/auth/providers/index.d.ts.map +1 -0
- package/dist/auth/providers/index.js +4 -0
- package/dist/auth/providers/index.js.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts +91 -0
- package/dist/auth/providers/jwt_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/jwt_auth_provider.js +204 -0
- package/dist/auth/providers/jwt_auth_provider.js.map +1 -0
- package/dist/auth/providers/no_auth_provider.d.ts +61 -0
- package/dist/auth/providers/no_auth_provider.d.ts.map +1 -0
- package/dist/auth/providers/no_auth_provider.js +76 -0
- package/dist/auth/providers/no_auth_provider.js.map +1 -0
- package/dist/auth/types.d.ts +100 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/user_service.d.ts +86 -0
- package/dist/auth/user_service.d.ts.map +1 -0
- package/dist/auth/user_service.js +237 -0
- package/dist/auth/user_service.js.map +1 -0
- package/dist/components/assets_manager.d.ts +662 -0
- package/dist/components/assets_manager.d.ts.map +1 -0
- package/dist/components/assets_manager.js +1537 -0
- package/dist/components/assets_manager.js.map +1 -0
- package/dist/components/async_upload.d.ts +20 -0
- package/dist/components/async_upload.d.ts.map +1 -0
- package/dist/components/async_upload.js +10 -0
- package/dist/components/async_upload.js.map +1 -0
- package/dist/components/collector.d.ts +203 -0
- package/dist/components/collector.d.ts.map +1 -0
- package/dist/components/collector.js +214 -0
- package/dist/components/collector.js.map +1 -0
- package/dist/components/custom_table_manager.d.ts +503 -0
- package/dist/components/custom_table_manager.d.ts.map +1 -0
- package/dist/components/custom_table_manager.js +1023 -0
- package/dist/components/custom_table_manager.js.map +1 -0
- package/dist/components/global_assets_handler.d.ts +63 -0
- package/dist/components/global_assets_handler.d.ts.map +1 -0
- package/dist/components/global_assets_handler.js +127 -0
- package/dist/components/global_assets_handler.js.map +1 -0
- package/dist/components/handler.d.ts +104 -0
- package/dist/components/handler.d.ts.map +1 -0
- package/dist/components/handler.js +110 -0
- package/dist/components/handler.js.map +1 -0
- package/dist/components/harvester.d.ts +182 -0
- package/dist/components/harvester.d.ts.map +1 -0
- package/dist/components/harvester.js +406 -0
- package/dist/components/harvester.js.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +9 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/interfaces.d.ts +126 -0
- package/dist/components/interfaces.d.ts.map +1 -0
- package/dist/components/interfaces.js +8 -0
- package/dist/components/interfaces.js.map +1 -0
- package/dist/components/map_manager.d.ts +61 -0
- package/dist/components/map_manager.d.ts.map +1 -0
- package/dist/components/map_manager.js +242 -0
- package/dist/components/map_manager.js.map +1 -0
- package/dist/components/tileset_manager.d.ts +125 -0
- package/dist/components/tileset_manager.d.ts.map +1 -0
- package/dist/components/tileset_manager.js +623 -0
- package/dist/components/tileset_manager.js.map +1 -0
- package/dist/components/types.d.ts +226 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +8 -0
- package/dist/components/types.js.map +1 -0
- package/dist/database/adapters/knex_database_adapter.d.ts +97 -0
- package/dist/database/adapters/knex_database_adapter.d.ts.map +1 -0
- package/dist/database/adapters/knex_database_adapter.js +729 -0
- package/dist/database/adapters/knex_database_adapter.js.map +1 -0
- package/dist/database/database_adapter.d.ts +262 -0
- package/dist/database/database_adapter.d.ts.map +1 -0
- package/dist/database/database_adapter.js +46 -0
- package/dist/database/database_adapter.js.map +1 -0
- package/dist/engine/digital_twin_engine.d.ts +295 -0
- package/dist/engine/digital_twin_engine.d.ts.map +1 -0
- package/dist/engine/digital_twin_engine.js +907 -0
- package/dist/engine/digital_twin_engine.js.map +1 -0
- package/dist/engine/endpoints.d.ts +47 -0
- package/dist/engine/endpoints.d.ts.map +1 -0
- package/dist/engine/endpoints.js +88 -0
- package/dist/engine/endpoints.js.map +1 -0
- package/dist/engine/error_handler.d.ts +20 -0
- package/dist/engine/error_handler.d.ts.map +1 -0
- package/dist/engine/error_handler.js +69 -0
- package/dist/engine/error_handler.js.map +1 -0
- package/dist/engine/events.d.ts +93 -0
- package/dist/engine/events.d.ts.map +1 -0
- package/dist/engine/events.js +71 -0
- package/dist/engine/events.js.map +1 -0
- package/dist/engine/health.d.ts +112 -0
- package/dist/engine/health.d.ts.map +1 -0
- package/dist/engine/health.js +190 -0
- package/dist/engine/health.js.map +1 -0
- package/dist/engine/initializer.d.ts +62 -0
- package/dist/engine/initializer.d.ts.map +1 -0
- package/dist/engine/initializer.js +108 -0
- package/dist/engine/initializer.js.map +1 -0
- package/dist/engine/queue_manager.d.ts +87 -0
- package/dist/engine/queue_manager.d.ts.map +1 -0
- package/dist/engine/queue_manager.js +196 -0
- package/dist/engine/queue_manager.js.map +1 -0
- package/dist/engine/scheduler.d.ts +30 -0
- package/dist/engine/scheduler.d.ts.map +1 -0
- package/dist/engine/scheduler.js +378 -0
- package/dist/engine/scheduler.js.map +1 -0
- package/dist/engine/upload_processor.d.ts +36 -0
- package/dist/engine/upload_processor.d.ts.map +1 -0
- package/dist/engine/upload_processor.js +113 -0
- package/dist/engine/upload_processor.js.map +1 -0
- package/dist/env/env.d.ts +134 -0
- package/dist/env/env.d.ts.map +1 -0
- package/dist/env/env.js +177 -0
- package/dist/env/env.js.map +1 -0
- package/dist/errors/index.d.ts +94 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +149 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/openapi/generator.d.ts +93 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +293 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/openapi/index.d.ts +9 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +9 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/types.d.ts +182 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi/types.js +16 -0
- package/dist/openapi/types.js.map +1 -0
- package/dist/storage/adapters/local_storage_service.d.ts +57 -0
- package/dist/storage/adapters/local_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/local_storage_service.js +132 -0
- package/dist/storage/adapters/local_storage_service.js.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts +72 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts.map +1 -0
- package/dist/storage/adapters/ovh_storage_service.js +205 -0
- package/dist/storage/adapters/ovh_storage_service.js.map +1 -0
- package/dist/storage/storage_factory.d.ts +14 -0
- package/dist/storage/storage_factory.d.ts.map +1 -0
- package/dist/storage/storage_factory.js +43 -0
- package/dist/storage/storage_factory.js.map +1 -0
- package/dist/storage/storage_service.d.ts +163 -0
- package/dist/storage/storage_service.d.ts.map +1 -0
- package/dist/storage/storage_service.js +58 -0
- package/dist/storage/storage_service.js.map +1 -0
- package/dist/types/data_record.d.ts +123 -0
- package/dist/types/data_record.d.ts.map +1 -0
- package/dist/types/data_record.js +8 -0
- package/dist/types/data_record.js.map +1 -0
- package/dist/utils/graceful_shutdown.d.ts +44 -0
- package/dist/utils/graceful_shutdown.d.ts.map +1 -0
- package/dist/utils/graceful_shutdown.js +79 -0
- package/dist/utils/graceful_shutdown.js.map +1 -0
- package/dist/utils/http_responses.d.ts +175 -0
- package/dist/utils/http_responses.d.ts.map +1 -0
- package/dist/utils/http_responses.js +216 -0
- package/dist/utils/http_responses.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +74 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +92 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/map_to_data_record.d.ts +10 -0
- package/dist/utils/map_to_data_record.d.ts.map +1 -0
- package/dist/utils/map_to_data_record.js +36 -0
- package/dist/utils/map_to_data_record.js.map +1 -0
- package/dist/utils/safe_async.d.ts +50 -0
- package/dist/utils/safe_async.d.ts.map +1 -0
- package/dist/utils/safe_async.js +90 -0
- package/dist/utils/safe_async.js.map +1 -0
- package/dist/utils/servable_endpoint.d.ts +63 -0
- package/dist/utils/servable_endpoint.d.ts.map +1 -0
- package/dist/utils/servable_endpoint.js +67 -0
- package/dist/utils/servable_endpoint.js.map +1 -0
- package/dist/utils/zip_utils.d.ts +66 -0
- package/dist/utils/zip_utils.d.ts.map +1 -0
- package/dist/utils/zip_utils.js +169 -0
- package/dist/utils/zip_utils.js.map +1 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.d.ts +273 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +82 -0
- package/dist/validation/schemas.js.map +1 -0
- package/dist/validation/validate.d.ts +49 -0
- package/dist/validation/validate.d.ts.map +1 -0
- package/dist/validation/validate.js +110 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +23 -13
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OVH Object Storage implementation of StorageService
|
|
3
|
+
* via S3-compatible API using @aws-sdk/client-s3
|
|
4
|
+
*/
|
|
5
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteObjectsCommand, ListObjectsV2Command, PutBucketCorsCommand, ObjectCannedACL } from '@aws-sdk/client-s3';
|
|
6
|
+
import { StorageService } from '../storage_service.js';
|
|
7
|
+
import { safeAsync } from '../../utils/safe_async.js';
|
|
8
|
+
import { Logger } from '../../utils/logger.js';
|
|
9
|
+
const logger = new Logger('OvhS3Storage');
|
|
10
|
+
export class OvhS3StorageService extends StorageService {
|
|
11
|
+
#s3;
|
|
12
|
+
#bucket;
|
|
13
|
+
#endpoint;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
super();
|
|
16
|
+
this.#bucket = config.bucket;
|
|
17
|
+
this.#endpoint = config.endpoint;
|
|
18
|
+
this.#s3 = new S3Client({
|
|
19
|
+
endpoint: config.endpoint,
|
|
20
|
+
region: config.region ?? 'gra',
|
|
21
|
+
credentials: {
|
|
22
|
+
accessKeyId: config.accessKey,
|
|
23
|
+
secretAccessKey: config.secretKey
|
|
24
|
+
},
|
|
25
|
+
forcePathStyle: false,
|
|
26
|
+
// Match Python boto3 config for OVH compatibility
|
|
27
|
+
requestChecksumCalculation: 'WHEN_REQUIRED',
|
|
28
|
+
responseChecksumValidation: 'WHEN_REQUIRED'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Uploads a file to the OVH S3-compatible object storage.
|
|
33
|
+
* @param buffer - File contents to upload
|
|
34
|
+
* @param collectorName - Folder/prefix to store under
|
|
35
|
+
* @param extension - Optional file extension (e.g. 'json')
|
|
36
|
+
* @returns The relative path (key) of the stored object
|
|
37
|
+
*/
|
|
38
|
+
async save(buffer, collectorName, extension) {
|
|
39
|
+
const now = new Date();
|
|
40
|
+
const timestamp = now.toISOString().replace(/[:.]/g, '-');
|
|
41
|
+
const key = `${collectorName || 'default'}/${timestamp}${extension ? '.' + extension : ''}`;
|
|
42
|
+
await this.#s3.send(new PutObjectCommand({
|
|
43
|
+
Bucket: this.#bucket,
|
|
44
|
+
Key: key,
|
|
45
|
+
Body: buffer,
|
|
46
|
+
ACL: ObjectCannedACL.private
|
|
47
|
+
}));
|
|
48
|
+
return key;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Downloads and returns a stored object as a Buffer.
|
|
52
|
+
* @param relativePath - The key/path of the object to retrieve
|
|
53
|
+
* @returns The object contents as a Buffer
|
|
54
|
+
*/
|
|
55
|
+
async retrieve(relativePath) {
|
|
56
|
+
const res = await this.#s3.send(new GetObjectCommand({
|
|
57
|
+
Bucket: this.#bucket,
|
|
58
|
+
Key: relativePath
|
|
59
|
+
}));
|
|
60
|
+
const chunks = [];
|
|
61
|
+
const stream = res.Body;
|
|
62
|
+
for await (const chunk of stream) {
|
|
63
|
+
chunks.push(Buffer.from(chunk));
|
|
64
|
+
}
|
|
65
|
+
return Buffer.concat(chunks);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Deletes an object from the storage bucket.
|
|
69
|
+
* @param relativePath - The key/path of the object to delete
|
|
70
|
+
*/
|
|
71
|
+
async delete(relativePath) {
|
|
72
|
+
await this.#s3.send(new DeleteObjectCommand({
|
|
73
|
+
Bucket: this.#bucket,
|
|
74
|
+
Key: relativePath
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Uploads a file to OVH S3 at a specific path (preserves filename).
|
|
79
|
+
* Unlike save(), this method does not auto-generate a timestamp filename.
|
|
80
|
+
* Files are uploaded with public-read ACL for direct access (e.g., Cesium tilesets).
|
|
81
|
+
* @param buffer - File contents to upload
|
|
82
|
+
* @param relativePath - Full relative path including filename (e.g., 'tilesets/123/tileset.json')
|
|
83
|
+
* @returns The same relative path that was provided
|
|
84
|
+
*/
|
|
85
|
+
async saveWithPath(buffer, relativePath) {
|
|
86
|
+
await this.#s3.send(new PutObjectCommand({
|
|
87
|
+
Bucket: this.#bucket,
|
|
88
|
+
Key: relativePath,
|
|
89
|
+
Body: buffer,
|
|
90
|
+
ACL: ObjectCannedACL.public_read
|
|
91
|
+
}));
|
|
92
|
+
return relativePath;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Deletes multiple objects in batch using S3 DeleteObjects API.
|
|
96
|
+
* Much faster than individual deletes - can delete up to 1000 objects per request.
|
|
97
|
+
* @param paths - Array of object keys to delete
|
|
98
|
+
*/
|
|
99
|
+
async deleteBatch(paths) {
|
|
100
|
+
if (paths.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
// S3 DeleteObjects supports max 1000 objects per request
|
|
103
|
+
const BATCH_SIZE = 1000;
|
|
104
|
+
const batches = [];
|
|
105
|
+
for (let i = 0; i < paths.length; i += BATCH_SIZE) {
|
|
106
|
+
batches.push(paths.slice(i, i + BATCH_SIZE));
|
|
107
|
+
}
|
|
108
|
+
// Process batches in parallel (but limit concurrency to avoid overwhelming the API)
|
|
109
|
+
const MAX_CONCURRENT = 5;
|
|
110
|
+
for (let i = 0; i < batches.length; i += MAX_CONCURRENT) {
|
|
111
|
+
const concurrentBatches = batches.slice(i, i + MAX_CONCURRENT);
|
|
112
|
+
await Promise.all(concurrentBatches.map((batch, index) => safeAsync(() => this.#s3.send(new DeleteObjectsCommand({
|
|
113
|
+
Bucket: this.#bucket,
|
|
114
|
+
Delete: {
|
|
115
|
+
Objects: batch.map(key => ({ Key: key })),
|
|
116
|
+
Quiet: true // Don't return info about each deleted object
|
|
117
|
+
}
|
|
118
|
+
})), `delete batch ${i + index + 1}/${batches.length}`, logger)));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns the public URL for a stored file.
|
|
123
|
+
* Constructs the OVH S3 public URL format: https://{bucket}.{endpoint_host}/{key}
|
|
124
|
+
* @param relativePath - The storage path/key of the file
|
|
125
|
+
* @returns The public URL to access the file directly
|
|
126
|
+
*/
|
|
127
|
+
getPublicUrl(relativePath) {
|
|
128
|
+
// Extract host from endpoint (e.g., 'https://s3.gra.io.cloud.ovh.net' -> 's3.gra.io.cloud.ovh.net')
|
|
129
|
+
const endpointHost = this.#endpoint.replace(/^https?:\/\//, '');
|
|
130
|
+
// OVH S3 URL format: https://{bucket}.{endpoint_host}/{key}
|
|
131
|
+
return `https://${this.#bucket}.${endpointHost}/${relativePath}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Deletes all objects under a given prefix (folder).
|
|
135
|
+
* Lists objects by prefix and deletes them in batches for performance.
|
|
136
|
+
* @param prefix - The folder/prefix to delete (e.g., 'tilesets/123')
|
|
137
|
+
* @returns Number of files deleted
|
|
138
|
+
*/
|
|
139
|
+
async deleteByPrefix(prefix) {
|
|
140
|
+
let totalDeleted = 0;
|
|
141
|
+
let continuationToken;
|
|
142
|
+
// Ensure prefix ends with '/' to avoid partial matches
|
|
143
|
+
const normalizedPrefix = prefix.endsWith('/') ? prefix : `${prefix}/`;
|
|
144
|
+
do {
|
|
145
|
+
// List objects with prefix (max 1000 per request)
|
|
146
|
+
const listResponse = await this.#s3.send(new ListObjectsV2Command({
|
|
147
|
+
Bucket: this.#bucket,
|
|
148
|
+
Prefix: normalizedPrefix,
|
|
149
|
+
ContinuationToken: continuationToken
|
|
150
|
+
}));
|
|
151
|
+
const objects = listResponse.Contents || [];
|
|
152
|
+
if (objects.length === 0)
|
|
153
|
+
break;
|
|
154
|
+
// Delete objects in batch
|
|
155
|
+
const keys = objects.map(obj => obj.Key).filter((key) => !!key);
|
|
156
|
+
if (keys.length > 0) {
|
|
157
|
+
await this.#s3.send(new DeleteObjectsCommand({
|
|
158
|
+
Bucket: this.#bucket,
|
|
159
|
+
Delete: {
|
|
160
|
+
Objects: keys.map(key => ({ Key: key })),
|
|
161
|
+
Quiet: true
|
|
162
|
+
}
|
|
163
|
+
}));
|
|
164
|
+
totalDeleted += keys.length;
|
|
165
|
+
}
|
|
166
|
+
continuationToken = listResponse.NextContinuationToken;
|
|
167
|
+
} while (continuationToken);
|
|
168
|
+
return totalDeleted;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Configure CORS settings for the bucket.
|
|
172
|
+
* Required for browser-based access to public files (e.g., Cesium loading tilesets).
|
|
173
|
+
* Should be called once during application startup.
|
|
174
|
+
*
|
|
175
|
+
* @param allowedOrigins - List of allowed origins (default: ['*'])
|
|
176
|
+
* @param allowedMethods - List of allowed HTTP methods (default: ['GET', 'HEAD'])
|
|
177
|
+
* @param allowedHeaders - List of allowed headers (default: ['*', 'Authorization'])
|
|
178
|
+
* @returns true if successful, false otherwise
|
|
179
|
+
*/
|
|
180
|
+
async configureCors(allowedOrigins = ['*'], allowedMethods = ['GET', 'HEAD'], allowedHeaders = ['*', 'Authorization']) {
|
|
181
|
+
try {
|
|
182
|
+
await this.#s3.send(new PutBucketCorsCommand({
|
|
183
|
+
Bucket: this.#bucket,
|
|
184
|
+
CORSConfiguration: {
|
|
185
|
+
CORSRules: [
|
|
186
|
+
{
|
|
187
|
+
AllowedOrigins: allowedOrigins,
|
|
188
|
+
AllowedMethods: allowedMethods,
|
|
189
|
+
AllowedHeaders: allowedHeaders,
|
|
190
|
+
ExposeHeaders: ['ETag', 'Content-Length'],
|
|
191
|
+
MaxAgeSeconds: 3000
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}));
|
|
196
|
+
console.log('[OvhS3StorageService] CORS configured successfully');
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
console.error('[OvhS3StorageService] Error configuring CORS:', error);
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=ovh_storage_service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ovh_storage_service.js","sourceRoot":"","sources":["../../../src/storage/adapters/ovh_storage_service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StorageService } from './storage_service.js';
|
|
2
|
+
export declare class StorageServiceFactory {
|
|
3
|
+
/**
|
|
4
|
+
* Creates and returns an instance of StorageService
|
|
5
|
+
* based on the STORAGE_CONFIG environment variable.
|
|
6
|
+
*
|
|
7
|
+
* - 'local': returns a LocalStorageService
|
|
8
|
+
* - 'ovh': returns an OvhS3StorageService
|
|
9
|
+
*
|
|
10
|
+
* @throws Error if STORAGE_CONFIG is not supported
|
|
11
|
+
*/
|
|
12
|
+
static create(): StorageService;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=storage_factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage_factory.d.ts","sourceRoot":"","sources":["../../src/storage/storage_factory.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAM1D,qBAAa,qBAAqB;IAC9B;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM,IAAI,cAAc;CAwBlC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory class for creating the appropriate StorageService
|
|
3
|
+
* implementation based on environment configuration.
|
|
4
|
+
*/
|
|
5
|
+
import { Env } from '../env/env.js';
|
|
6
|
+
import { OvhS3StorageService } from './adapters/ovh_storage_service.js';
|
|
7
|
+
import { LocalStorageService } from './adapters/local_storage_service.js';
|
|
8
|
+
import { safeAsync } from '../utils/safe_async.js';
|
|
9
|
+
import { Logger } from '../utils/logger.js';
|
|
10
|
+
const logger = new Logger('StorageFactory');
|
|
11
|
+
export class StorageServiceFactory {
|
|
12
|
+
/**
|
|
13
|
+
* Creates and returns an instance of StorageService
|
|
14
|
+
* based on the STORAGE_CONFIG environment variable.
|
|
15
|
+
*
|
|
16
|
+
* - 'local': returns a LocalStorageService
|
|
17
|
+
* - 'ovh': returns an OvhS3StorageService
|
|
18
|
+
*
|
|
19
|
+
* @throws Error if STORAGE_CONFIG is not supported
|
|
20
|
+
*/
|
|
21
|
+
static create() {
|
|
22
|
+
const env = Env.config;
|
|
23
|
+
switch (env.STORAGE_CONFIG) {
|
|
24
|
+
case 'local':
|
|
25
|
+
return new LocalStorageService(env.LOCAL_STORAGE_DIR || 'data');
|
|
26
|
+
case 'ovh': {
|
|
27
|
+
const ovhStorage = new OvhS3StorageService({
|
|
28
|
+
accessKey: env.OVH_ACCESS_KEY,
|
|
29
|
+
secretKey: env.OVH_SECRET_KEY,
|
|
30
|
+
endpoint: env.OVH_ENDPOINT,
|
|
31
|
+
bucket: env.OVH_BUCKET,
|
|
32
|
+
region: env.OVH_REGION ?? 'gra'
|
|
33
|
+
});
|
|
34
|
+
// Configure CORS for browser access (non-blocking)
|
|
35
|
+
safeAsync(() => ovhStorage.configureCors(), 'configure OVH CORS', logger);
|
|
36
|
+
return ovhStorage;
|
|
37
|
+
}
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(`Unsupported STORAGE_CONFIG: ${env.STORAGE_CONFIG}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=storage_factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage_factory.js","sourceRoot":"","sources":["../../src/storage/storage_factory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAA;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AAE3C,MAAM,OAAO,qBAAqB;IAC9B;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM;QACT,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAA;QAEtB,QAAQ,GAAG,CAAC,cAAc,EAAE,CAAC;YACzB,KAAK,OAAO;gBACR,OAAO,IAAI,mBAAmB,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,CAAC,CAAA;YAEnE,KAAK,KAAK,CAAC,CAAC,CAAC;gBACT,MAAM,UAAU,GAAG,IAAI,mBAAmB,CAAC;oBACvC,SAAS,EAAE,GAAG,CAAC,cAAc;oBAC7B,SAAS,EAAE,GAAG,CAAC,cAAc;oBAC7B,QAAQ,EAAE,GAAG,CAAC,YAAY;oBAC1B,MAAM,EAAE,GAAG,CAAC,UAAU;oBACtB,MAAM,EAAE,GAAG,CAAC,UAAU,IAAI,KAAK;iBAClC,CAAC,CAAA;gBACF,mDAAmD;gBACnD,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;gBACzE,OAAO,UAAU,CAAA;YACrB,CAAC;YAED;gBACI,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,cAAc,EAAE,CAAC,CAAA;QAC5E,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base class for storage service implementations.
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for persisting and retrieving binary data in the Digital Twin framework.
|
|
5
|
+
* Concrete implementations provide storage backends like local filesystem, AWS S3, Azure Blob, etc.
|
|
6
|
+
*
|
|
7
|
+
* @abstract
|
|
8
|
+
* @class StorageService
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Implement for specific storage backend
|
|
13
|
+
* class S3StorageService extends StorageService {
|
|
14
|
+
* async save(buffer: Buffer, collectorName: string, extension?: string): Promise<string> {
|
|
15
|
+
* // Upload to S3 bucket
|
|
16
|
+
* return 's3://bucket/path/to/file'
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* async retrieve(path: string): Promise<Buffer> {
|
|
20
|
+
* // Download from S3
|
|
21
|
+
* return buffer
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* async delete(path: string): Promise<void> {
|
|
25
|
+
* // Delete from S3
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare abstract class StorageService {
|
|
31
|
+
/**
|
|
32
|
+
* Persists binary data and returns a unique identifier for retrieval.
|
|
33
|
+
*
|
|
34
|
+
* The storage implementation should ensure the returned path/URL is unique
|
|
35
|
+
* and can be used later to retrieve the exact same data.
|
|
36
|
+
*
|
|
37
|
+
* @abstract
|
|
38
|
+
* @param {Buffer} buffer - Binary data to store
|
|
39
|
+
* @param {string} collectorName - Component name for organizing storage (used as folder/prefix)
|
|
40
|
+
* @param {string} extension - Optional file extension for proper content handling
|
|
41
|
+
* @returns {Promise<string>} Unique storage identifier (path, URL, or key)
|
|
42
|
+
* @throws {Error} When storage operation fails
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const buffer = Buffer.from('{"temperature": 23.5}')
|
|
47
|
+
* const path = await storage.save(buffer, 'weather-sensor', 'json')
|
|
48
|
+
* // Returns: '/storage/weather-sensor/2024-01-15_14-30-00.json'
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
abstract save(buffer: Buffer, collectorName: string, extension?: string): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves previously stored binary data.
|
|
54
|
+
*
|
|
55
|
+
* Uses the identifier returned by save() to fetch the original data.
|
|
56
|
+
*
|
|
57
|
+
* @abstract
|
|
58
|
+
* @param {string} path - Storage identifier from save() operation
|
|
59
|
+
* @returns {Promise<Buffer>} The original binary data
|
|
60
|
+
* @throws {Error} When file doesn't exist or retrieval fails
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const path = '/storage/weather-sensor/2024-01-15_14-30-00.json'
|
|
65
|
+
* const data = await storage.retrieve(path)
|
|
66
|
+
* const json = JSON.parse(data.toString())
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
abstract retrieve(path: string): Promise<Buffer>;
|
|
70
|
+
/**
|
|
71
|
+
* Removes stored data permanently.
|
|
72
|
+
*
|
|
73
|
+
* Deletes the data associated with the given storage identifier.
|
|
74
|
+
*
|
|
75
|
+
* @abstract
|
|
76
|
+
* @param {string} path - Storage identifier from save() operation
|
|
77
|
+
* @returns {Promise<void>}
|
|
78
|
+
* @throws {Error} When deletion fails or path doesn't exist
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const path = '/storage/weather-sensor/old-data.json'
|
|
83
|
+
* await storage.delete(path)
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
abstract delete(path: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Persists binary data at a specific path (no auto-generated filename).
|
|
89
|
+
*
|
|
90
|
+
* Unlike save(), this method stores the file at the exact path specified,
|
|
91
|
+
* preserving the original filename and directory structure.
|
|
92
|
+
* Useful for extracting archives where file paths must be preserved.
|
|
93
|
+
*
|
|
94
|
+
* @param {Buffer} buffer - Binary data to store
|
|
95
|
+
* @param {string} relativePath - Full relative path including filename (e.g., 'tilesets/123/tileset.json')
|
|
96
|
+
* @returns {Promise<string>} The same path that was provided (for consistency)
|
|
97
|
+
* @throws {Error} When storage operation fails
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const buffer = Buffer.from('{"asset": {"version": "1.0"}}')
|
|
102
|
+
* const path = await storage.saveWithPath(buffer, 'tilesets/123/tileset.json')
|
|
103
|
+
* // Returns: 'tilesets/123/tileset.json'
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
abstract saveWithPath(buffer: Buffer, relativePath: string): Promise<string>;
|
|
107
|
+
/**
|
|
108
|
+
* Deletes multiple files in batch for better performance.
|
|
109
|
+
*
|
|
110
|
+
* Default implementation calls delete() sequentially, but storage backends
|
|
111
|
+
* can override this with optimized bulk delete operations (e.g., S3 DeleteObjects).
|
|
112
|
+
*
|
|
113
|
+
* @param {string[]} paths - Array of storage identifiers to delete
|
|
114
|
+
* @returns {Promise<void>}
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* await storage.deleteBatch([
|
|
119
|
+
* 'tilesets/123/tileset.json',
|
|
120
|
+
* 'tilesets/123/tile_0.b3dm',
|
|
121
|
+
* 'tilesets/123/tile_1.b3dm'
|
|
122
|
+
* ])
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
deleteBatch(paths: string[]): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* Returns the public URL for a stored file.
|
|
128
|
+
*
|
|
129
|
+
* For cloud storage (S3, OVH, Azure), this returns the direct HTTP URL.
|
|
130
|
+
* For local storage, this may return a relative path or throw an error.
|
|
131
|
+
*
|
|
132
|
+
* @abstract
|
|
133
|
+
* @param {string} relativePath - The storage path/key of the file
|
|
134
|
+
* @returns {string} The public URL to access the file directly
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const url = storage.getPublicUrl('tilesets/123/tileset.json')
|
|
139
|
+
* // Returns: 'https://bucket.s3.region.cloud.ovh.net/tilesets/123/tileset.json'
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
abstract getPublicUrl(relativePath: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* Deletes all files under a given prefix/folder.
|
|
145
|
+
*
|
|
146
|
+
* This is more efficient than deleteBatch() when you don't know all file paths,
|
|
147
|
+
* as it lists objects by prefix and deletes them in bulk.
|
|
148
|
+
* Useful for deleting entire tilesets or component data.
|
|
149
|
+
*
|
|
150
|
+
* @abstract
|
|
151
|
+
* @param {string} prefix - The folder/prefix to delete (e.g., 'tilesets/123')
|
|
152
|
+
* @returns {Promise<number>} Number of files deleted
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const count = await storage.deleteByPrefix('tilesets/123')
|
|
157
|
+
* // Deletes all files starting with 'tilesets/123/'
|
|
158
|
+
* console.log(`Deleted ${count} files`)
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
abstract deleteByPrefix(prefix: string): Promise<number>;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=storage_service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage_service.d.ts","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,8BAAsB,cAAc;IAChC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAEzF;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAEhD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAE5C;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE5E;;;;;;;;;;;;;;;;;OAiBG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAEnD;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAC3D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { safeAsync } from '../utils/safe_async.js';
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
const logger = new Logger('StorageService');
|
|
4
|
+
/**
|
|
5
|
+
* Abstract base class for storage service implementations.
|
|
6
|
+
*
|
|
7
|
+
* Defines the contract for persisting and retrieving binary data in the Digital Twin framework.
|
|
8
|
+
* Concrete implementations provide storage backends like local filesystem, AWS S3, Azure Blob, etc.
|
|
9
|
+
*
|
|
10
|
+
* @abstract
|
|
11
|
+
* @class StorageService
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Implement for specific storage backend
|
|
16
|
+
* class S3StorageService extends StorageService {
|
|
17
|
+
* async save(buffer: Buffer, collectorName: string, extension?: string): Promise<string> {
|
|
18
|
+
* // Upload to S3 bucket
|
|
19
|
+
* return 's3://bucket/path/to/file'
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* async retrieve(path: string): Promise<Buffer> {
|
|
23
|
+
* // Download from S3
|
|
24
|
+
* return buffer
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* async delete(path: string): Promise<void> {
|
|
28
|
+
* // Delete from S3
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class StorageService {
|
|
34
|
+
/**
|
|
35
|
+
* Deletes multiple files in batch for better performance.
|
|
36
|
+
*
|
|
37
|
+
* Default implementation calls delete() sequentially, but storage backends
|
|
38
|
+
* can override this with optimized bulk delete operations (e.g., S3 DeleteObjects).
|
|
39
|
+
*
|
|
40
|
+
* @param {string[]} paths - Array of storage identifiers to delete
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* await storage.deleteBatch([
|
|
46
|
+
* 'tilesets/123/tileset.json',
|
|
47
|
+
* 'tilesets/123/tile_0.b3dm',
|
|
48
|
+
* 'tilesets/123/tile_1.b3dm'
|
|
49
|
+
* ])
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
async deleteBatch(paths) {
|
|
53
|
+
// Default parallel implementation - subclasses can override with bulk operations
|
|
54
|
+
// Individual failures are logged but don't prevent other deletions
|
|
55
|
+
await Promise.all(paths.map(path => safeAsync(() => this.delete(path), `delete file ${path}`, logger)));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=storage_service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage_service.js","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAgB,cAAc;IAiFhC;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,WAAW,CAAC,KAAe;QAC7B,iFAAiF;QACjF,mEAAmE;QACnE,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,eAAe,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAC3G,CAAC;CAuCJ"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Data record type definition for digital twin data storage
|
|
3
|
+
*
|
|
4
|
+
* This module defines the standardized interface for data records used
|
|
5
|
+
* throughout the digital twin system for both streaming data and asset storage.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Standard data record interface for digital twin data storage.
|
|
9
|
+
*
|
|
10
|
+
* DataRecord provides a unified interface for all data stored in the digital twin system,
|
|
11
|
+
* from streaming sensor data to asset files. It supports both database metadata
|
|
12
|
+
* and file storage through a consistent API.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const record: DataRecord = {
|
|
17
|
+
* id: 12345,
|
|
18
|
+
* name: 'weather-station-001',
|
|
19
|
+
* date: new Date(),
|
|
20
|
+
* contentType: 'application/json',
|
|
21
|
+
* url: '/api/data/weather/12345',
|
|
22
|
+
* data: async () => Buffer.from(JSON.stringify(weatherData)),
|
|
23
|
+
* description: 'Weather data from station 001',
|
|
24
|
+
* source: 'https://api.weather.com/v1/current',
|
|
25
|
+
* owner_id: 123
|
|
26
|
+
* };
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export interface DataRecord {
|
|
30
|
+
/** Unique identifier for this data record */
|
|
31
|
+
id: number;
|
|
32
|
+
/** Human-readable name or identifier for this record */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Timestamp when this record was created or last updated */
|
|
35
|
+
date: Date;
|
|
36
|
+
/** MIME type of the data content (e.g., 'application/json', 'image/png') */
|
|
37
|
+
contentType: string;
|
|
38
|
+
/** URL or path where this record can be accessed */
|
|
39
|
+
url: string;
|
|
40
|
+
/**
|
|
41
|
+
* Function that returns the actual data content as a Buffer.
|
|
42
|
+
*
|
|
43
|
+
* This lazy-loading approach allows for efficient memory usage
|
|
44
|
+
* when working with large datasets or files.
|
|
45
|
+
*
|
|
46
|
+
* @returns Promise resolving to the data content as a Buffer
|
|
47
|
+
*/
|
|
48
|
+
data: () => Promise<Buffer>;
|
|
49
|
+
/**
|
|
50
|
+
* Human-readable description of the asset.
|
|
51
|
+
*
|
|
52
|
+
* Used primarily by AssetsManager components to provide
|
|
53
|
+
* additional context about stored files and resources.
|
|
54
|
+
*/
|
|
55
|
+
description?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Source URL for data provenance.
|
|
58
|
+
*
|
|
59
|
+
* Records the original source of this data for traceability
|
|
60
|
+
* and debugging purposes. Used by AssetsManager components.
|
|
61
|
+
*/
|
|
62
|
+
source?: string;
|
|
63
|
+
/**
|
|
64
|
+
* ID of the user who owns this asset.
|
|
65
|
+
*
|
|
66
|
+
* Enables access control and ownership tracking for
|
|
67
|
+
* asset management. Used by AssetsManager components.
|
|
68
|
+
*/
|
|
69
|
+
owner_id?: number | null;
|
|
70
|
+
/**
|
|
71
|
+
* Original filename provided by the user.
|
|
72
|
+
*
|
|
73
|
+
* Preserves the original filename when assets are uploaded
|
|
74
|
+
* or imported. Used by AssetsManager components.
|
|
75
|
+
*/
|
|
76
|
+
filename?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Whether the asset is publicly accessible.
|
|
79
|
+
*
|
|
80
|
+
* Controls visibility of assets. If true, asset can be accessed
|
|
81
|
+
* by anyone. If false, only the owner can access it.
|
|
82
|
+
* Used by AssetsManager components for access control.
|
|
83
|
+
*/
|
|
84
|
+
is_public?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Public URL to tileset.json for Cesium loading.
|
|
87
|
+
* Cesium accesses files directly via this URL.
|
|
88
|
+
*/
|
|
89
|
+
tileset_url?: string;
|
|
90
|
+
/**
|
|
91
|
+
* @deprecated No longer used. Kept for backward compatibility.
|
|
92
|
+
*/
|
|
93
|
+
file_index?: {
|
|
94
|
+
/** List of files with their storage paths */
|
|
95
|
+
files: Array<{
|
|
96
|
+
/** Storage path for this file */
|
|
97
|
+
path: string;
|
|
98
|
+
/** Original filename */
|
|
99
|
+
name: string;
|
|
100
|
+
/** File size in bytes */
|
|
101
|
+
size?: number;
|
|
102
|
+
}>;
|
|
103
|
+
/** Main entry point file (e.g., 'tileset.json') */
|
|
104
|
+
root_file?: string;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Status of async upload processing.
|
|
108
|
+
* - 'pending': Job queued, waiting to start
|
|
109
|
+
* - 'processing': Job is running
|
|
110
|
+
* - 'completed': Job finished successfully
|
|
111
|
+
* - 'failed': Job failed with error
|
|
112
|
+
*/
|
|
113
|
+
upload_status?: 'pending' | 'processing' | 'completed' | 'failed' | null;
|
|
114
|
+
/**
|
|
115
|
+
* Error message if upload failed.
|
|
116
|
+
*/
|
|
117
|
+
upload_error?: string | null;
|
|
118
|
+
/**
|
|
119
|
+
* BullMQ job ID for tracking.
|
|
120
|
+
*/
|
|
121
|
+
upload_job_id?: string | null;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=data_record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data_record.d.ts","sourceRoot":"","sources":["../../src/types/data_record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,UAAU;IACvB,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAA;IAEV,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IAEZ,6DAA6D;IAC7D,IAAI,EAAE,IAAI,CAAA;IAEV,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IAEnB,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAA;IAEX;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAI3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAExB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAInB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAIpB;;OAEG;IACH,UAAU,CAAC,EAAE;QACT,6CAA6C;QAC7C,KAAK,EAAE,KAAK,CAAC;YACT,iCAAiC;YACjC,IAAI,EAAE,MAAM,CAAA;YACZ,wBAAwB;YACxB,IAAI,EAAE,MAAM,CAAA;YACZ,yBAAyB;YACzB,IAAI,CAAC,EAAE,MAAM,CAAA;SAChB,CAAC,CAAA;QACF,mDAAmD;QACnD,SAAS,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;IAID;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAA;IAExE;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAE5B;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Data record type definition for digital twin data storage
|
|
3
|
+
*
|
|
4
|
+
* This module defines the standardized interface for data records used
|
|
5
|
+
* throughout the digital twin system for both streaming data and asset storage.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=data_record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data_record.js","sourceRoot":"","sources":["../../src/types/data_record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|