digitaltwin-core 0.13.1 → 0.13.3
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/dist/components/tileset_manager.d.ts +45 -56
- package/dist/components/tileset_manager.d.ts.map +1 -1
- package/dist/components/tileset_manager.js +370 -497
- package/dist/components/tileset_manager.js.map +1 -1
- package/dist/database/adapters/knex_database_adapter.d.ts.map +1 -1
- package/dist/database/adapters/knex_database_adapter.js +9 -12
- package/dist/database/adapters/knex_database_adapter.js.map +1 -1
- package/dist/engine/upload_processor.d.ts +6 -0
- package/dist/engine/upload_processor.d.ts.map +1 -1
- package/dist/engine/upload_processor.js +35 -10
- package/dist/engine/upload_processor.js.map +1 -1
- package/dist/storage/adapters/local_storage_service.d.ts +14 -0
- package/dist/storage/adapters/local_storage_service.d.ts.map +1 -1
- package/dist/storage/adapters/local_storage_service.js +46 -0
- package/dist/storage/adapters/local_storage_service.js.map +1 -1
- package/dist/storage/adapters/ovh_storage_service.d.ts +15 -0
- package/dist/storage/adapters/ovh_storage_service.d.ts.map +1 -1
- package/dist/storage/adapters/ovh_storage_service.js +59 -4
- package/dist/storage/adapters/ovh_storage_service.js.map +1 -1
- package/dist/storage/storage_service.d.ts +36 -0
- package/dist/storage/storage_service.d.ts.map +1 -1
- package/dist/storage/storage_service.js.map +1 -1
- package/dist/types/data_record.d.ts +6 -15
- package/dist/types/data_record.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/map_to_data_record.d.ts.map +1 -1
- package/dist/utils/map_to_data_record.js +3 -1
- package/dist/utils/map_to_data_record.js.map +1 -1
- package/dist/utils/zip_utils.d.ts +14 -30
- package/dist/utils/zip_utils.d.ts.map +1 -1
- package/dist/utils/zip_utils.js +25 -63
- package/dist/utils/zip_utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* OVH Object Storage implementation of StorageService
|
|
3
3
|
* via S3-compatible API using @aws-sdk/client-s3
|
|
4
4
|
*/
|
|
5
|
-
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteObjectsCommand } from '@aws-sdk/client-s3';
|
|
5
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteObjectsCommand, ListObjectsV2Command, ObjectCannedACL } from '@aws-sdk/client-s3';
|
|
6
6
|
import { StorageService } from '../storage_service.js';
|
|
7
7
|
export class OvhS3StorageService extends StorageService {
|
|
8
8
|
#s3;
|
|
9
9
|
#bucket;
|
|
10
|
+
#endpoint;
|
|
10
11
|
constructor(config) {
|
|
11
12
|
super();
|
|
12
13
|
this.#bucket = config.bucket;
|
|
14
|
+
this.#endpoint = config.endpoint;
|
|
13
15
|
this.#s3 = new S3Client({
|
|
14
16
|
endpoint: config.endpoint,
|
|
15
17
|
region: config.region ?? 'gra',
|
|
@@ -17,7 +19,10 @@ export class OvhS3StorageService extends StorageService {
|
|
|
17
19
|
accessKeyId: config.accessKey,
|
|
18
20
|
secretAccessKey: config.secretKey
|
|
19
21
|
},
|
|
20
|
-
forcePathStyle: false
|
|
22
|
+
forcePathStyle: false,
|
|
23
|
+
// Match Python boto3 config for OVH compatibility
|
|
24
|
+
requestChecksumCalculation: 'WHEN_REQUIRED',
|
|
25
|
+
responseChecksumValidation: 'WHEN_REQUIRED'
|
|
21
26
|
});
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
@@ -35,7 +40,7 @@ export class OvhS3StorageService extends StorageService {
|
|
|
35
40
|
Bucket: this.#bucket,
|
|
36
41
|
Key: key,
|
|
37
42
|
Body: buffer,
|
|
38
|
-
ACL:
|
|
43
|
+
ACL: ObjectCannedACL.private
|
|
39
44
|
}));
|
|
40
45
|
return key;
|
|
41
46
|
}
|
|
@@ -69,6 +74,7 @@ export class OvhS3StorageService extends StorageService {
|
|
|
69
74
|
/**
|
|
70
75
|
* Uploads a file to OVH S3 at a specific path (preserves filename).
|
|
71
76
|
* Unlike save(), this method does not auto-generate a timestamp filename.
|
|
77
|
+
* Files are uploaded with public-read ACL for direct access (e.g., Cesium tilesets).
|
|
72
78
|
* @param buffer - File contents to upload
|
|
73
79
|
* @param relativePath - Full relative path including filename (e.g., 'tilesets/123/tileset.json')
|
|
74
80
|
* @returns The same relative path that was provided
|
|
@@ -78,7 +84,7 @@ export class OvhS3StorageService extends StorageService {
|
|
|
78
84
|
Bucket: this.#bucket,
|
|
79
85
|
Key: relativePath,
|
|
80
86
|
Body: buffer,
|
|
81
|
-
ACL:
|
|
87
|
+
ACL: ObjectCannedACL.public_read
|
|
82
88
|
}));
|
|
83
89
|
return relativePath;
|
|
84
90
|
}
|
|
@@ -113,5 +119,54 @@ export class OvhS3StorageService extends StorageService {
|
|
|
113
119
|
})));
|
|
114
120
|
}
|
|
115
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Returns the public URL for a stored file.
|
|
124
|
+
* Constructs the OVH S3 public URL format: https://{bucket}.{endpoint_host}/{key}
|
|
125
|
+
* @param relativePath - The storage path/key of the file
|
|
126
|
+
* @returns The public URL to access the file directly
|
|
127
|
+
*/
|
|
128
|
+
getPublicUrl(relativePath) {
|
|
129
|
+
// Extract host from endpoint (e.g., 'https://s3.gra.io.cloud.ovh.net' -> 's3.gra.io.cloud.ovh.net')
|
|
130
|
+
const endpointHost = this.#endpoint.replace(/^https?:\/\//, '');
|
|
131
|
+
// OVH S3 URL format: https://{bucket}.{endpoint_host}/{key}
|
|
132
|
+
return `https://${this.#bucket}.${endpointHost}/${relativePath}`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Deletes all objects under a given prefix (folder).
|
|
136
|
+
* Lists objects by prefix and deletes them in batches for performance.
|
|
137
|
+
* @param prefix - The folder/prefix to delete (e.g., 'tilesets/123')
|
|
138
|
+
* @returns Number of files deleted
|
|
139
|
+
*/
|
|
140
|
+
async deleteByPrefix(prefix) {
|
|
141
|
+
let totalDeleted = 0;
|
|
142
|
+
let continuationToken;
|
|
143
|
+
// Ensure prefix ends with '/' to avoid partial matches
|
|
144
|
+
const normalizedPrefix = prefix.endsWith('/') ? prefix : `${prefix}/`;
|
|
145
|
+
do {
|
|
146
|
+
// List objects with prefix (max 1000 per request)
|
|
147
|
+
const listResponse = await this.#s3.send(new ListObjectsV2Command({
|
|
148
|
+
Bucket: this.#bucket,
|
|
149
|
+
Prefix: normalizedPrefix,
|
|
150
|
+
ContinuationToken: continuationToken
|
|
151
|
+
}));
|
|
152
|
+
const objects = listResponse.Contents || [];
|
|
153
|
+
if (objects.length === 0)
|
|
154
|
+
break;
|
|
155
|
+
// Delete objects in batch
|
|
156
|
+
const keys = objects.map(obj => obj.Key).filter((key) => !!key);
|
|
157
|
+
if (keys.length > 0) {
|
|
158
|
+
await this.#s3.send(new DeleteObjectsCommand({
|
|
159
|
+
Bucket: this.#bucket,
|
|
160
|
+
Delete: {
|
|
161
|
+
Objects: keys.map(key => ({ Key: key })),
|
|
162
|
+
Quiet: true
|
|
163
|
+
}
|
|
164
|
+
}));
|
|
165
|
+
totalDeleted += keys.length;
|
|
166
|
+
}
|
|
167
|
+
continuationToken = listResponse.NextContinuationToken;
|
|
168
|
+
} while (continuationToken);
|
|
169
|
+
return totalDeleted;
|
|
170
|
+
}
|
|
116
171
|
}
|
|
117
172
|
//# sourceMappingURL=ovh_storage_service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ovh_storage_service.js","sourceRoot":"","sources":["../../../src/storage/adapters/ovh_storage_service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACH,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"ovh_storage_service.js","sourceRoot":"","sources":["../../../src/storage/adapters/ovh_storage_service.ts"],"names":[],"mappings":"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"}
|
|
@@ -123,5 +123,41 @@ export declare abstract class StorageService {
|
|
|
123
123
|
* ```
|
|
124
124
|
*/
|
|
125
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>;
|
|
126
162
|
}
|
|
127
163
|
//# sourceMappingURL=storage_service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_service.d.ts","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;
|
|
1
|
+
{"version":3,"file":"storage_service.d.ts","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;IAKjD;;;;;;;;;;;;;;;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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage_service.js","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAgB,cAAc;IAiFhC;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,WAAW,CAAC,KAAe;QAC7B,mFAAmF;QACnF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3E,CAAC;
|
|
1
|
+
{"version":3,"file":"storage_service.js","sourceRoot":"","sources":["../../src/storage/storage_service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAgB,cAAc;IAiFhC;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,WAAW,CAAC,KAAe;QAC7B,mFAAmF;QACnF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3E,CAAC;CAuCJ"}
|
|
@@ -83,21 +83,12 @@ export interface DataRecord {
|
|
|
83
83
|
*/
|
|
84
84
|
is_public?: boolean;
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
* @
|
|
92
|
-
* ```typescript
|
|
93
|
-
* file_index: {
|
|
94
|
-
* files: [
|
|
95
|
-
* { path: 'tilesets/123/tileset.json', name: 'tileset.json', size: 1024 },
|
|
96
|
-
* { path: 'tilesets/123/tile_0.b3dm', name: 'tile_0.b3dm', size: 50000 }
|
|
97
|
-
* ],
|
|
98
|
-
* root_file: 'tileset.json'
|
|
99
|
-
* }
|
|
100
|
-
* ```
|
|
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.
|
|
101
92
|
*/
|
|
102
93
|
file_index?: {
|
|
103
94
|
/** List of files with their storage paths */
|
|
@@ -1 +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
|
|
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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Logger, LogLevel } from './logger.js';
|
|
2
2
|
export { mapToDataRecord } from './map_to_data_record.js';
|
|
3
3
|
export { servableEndpoint } from './servable_endpoint.js';
|
|
4
|
-
export { extractZipContentStream, zipToDict,
|
|
4
|
+
export { extractZipContentStream, zipToDict, detectTilesetRootFile, normalizeArchivePaths, extractAndStoreArchive } from './zip_utils.js';
|
|
5
5
|
export type { ExtractedArchiveResult } from './zip_utils.js';
|
|
6
6
|
export { HttpStatus, jsonResponse, successResponse, errorResponse, badRequestResponse, unauthorizedResponse, forbiddenResponse, notFoundResponse, textResponse, fileResponse, multiStatusResponse } from './http_responses.js';
|
|
7
7
|
export type { HttpStatusCode } from './http_responses.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EACH,uBAAuB,EACvB,SAAS,EACT,qBAAqB,EACrB,qBAAqB,EACrB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EACH,uBAAuB,EACvB,SAAS,EACT,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACtB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { Logger, LogLevel } from './logger.js';
|
|
2
2
|
export { mapToDataRecord } from './map_to_data_record.js';
|
|
3
3
|
export { servableEndpoint } from './servable_endpoint.js';
|
|
4
|
-
export { extractZipContentStream, zipToDict,
|
|
4
|
+
export { extractZipContentStream, zipToDict, detectTilesetRootFile, normalizeArchivePaths, extractAndStoreArchive } from './zip_utils.js';
|
|
5
5
|
export { HttpStatus, jsonResponse, successResponse, errorResponse, badRequestResponse, unauthorizedResponse, forbiddenResponse, notFoundResponse, textResponse, fileResponse, multiStatusResponse } from './http_responses.js';
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EACH,uBAAuB,EACvB,SAAS,EACT,qBAAqB,EACrB,qBAAqB,EACrB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EACH,uBAAuB,EACvB,SAAS,EACT,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACzB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACH,UAAU,EACV,YAAY,EACZ,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACtB,MAAM,qBAAqB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map_to_data_record.d.ts","sourceRoot":"","sources":["../../src/utils/map_to_data_record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,EAAE,OAAO,EAAE,cAAc,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"map_to_data_record.d.ts","sourceRoot":"","sources":["../../src/utils/map_to_data_record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,EAAE,OAAO,EAAE,cAAc,GAAG,UAAU,CAiC3F"}
|
|
@@ -19,7 +19,9 @@ export function mapToDataRecord(row, storage) {
|
|
|
19
19
|
// Default to true for backward compatibility with records created before is_public column
|
|
20
20
|
// SQLite stores booleans as 0/1, so we normalize to proper boolean
|
|
21
21
|
is_public: row.is_public === undefined || row.is_public === null ? true : Boolean(row.is_public),
|
|
22
|
-
//
|
|
22
|
+
// TilesetManager support
|
|
23
|
+
tileset_url: row.tileset_url || undefined,
|
|
24
|
+
// Legacy (deprecated)
|
|
23
25
|
file_index: row.file_index
|
|
24
26
|
? typeof row.file_index === 'string'
|
|
25
27
|
? JSON.parse(row.file_index)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map_to_data_record.js","sourceRoot":"","sources":["../../src/utils/map_to_data_record.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAsB,EAAE,OAAuB;IAC3E,OAAO;QACH,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,WAAW,EAAE,GAAG,CAAC,IAAI;QACrB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;QAErC,2DAA2D;QAC3D,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,0FAA0F;QAC1F,mEAAmE;QACnE,SAAS,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAEhG
|
|
1
|
+
{"version":3,"file":"map_to_data_record.js","sourceRoot":"","sources":["../../src/utils/map_to_data_record.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAsB,EAAE,OAAuB;IAC3E,OAAO;QACH,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,WAAW,EAAE,GAAG,CAAC,IAAI;QACrB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;QAErC,2DAA2D;QAC3D,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,0FAA0F;QAC1F,mEAAmE;QACnE,SAAS,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAEhG,yBAAyB;QACzB,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS;QAEzC,sBAAsB;QACtB,UAAU,EAAE,GAAG,CAAC,UAAU;YACtB,CAAC,CAAC,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ;gBAChC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;gBAC5B,CAAC,CAAC,GAAG,CAAC,UAAU;YACpB,CAAC,CAAC,SAAS;QAEf,uBAAuB;QACvB,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,IAAI;QACxC,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,IAAI;QACtC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,IAAI;KAC3C,CAAA;AACL,CAAC"}
|
|
@@ -3,16 +3,7 @@ import type { StorageService } from '../storage/storage_service.js';
|
|
|
3
3
|
* Result of extracting and storing a ZIP archive
|
|
4
4
|
*/
|
|
5
5
|
export interface ExtractedArchiveResult {
|
|
6
|
-
/**
|
|
7
|
-
files: Array<{
|
|
8
|
-
/** Storage path for this file */
|
|
9
|
-
path: string;
|
|
10
|
-
/** Original filename within the archive */
|
|
11
|
-
name: string;
|
|
12
|
-
/** File size in bytes */
|
|
13
|
-
size: number;
|
|
14
|
-
}>;
|
|
15
|
-
/** The root/main file (e.g., tileset.json) */
|
|
6
|
+
/** The root/main file path (e.g., 'tileset.json') */
|
|
16
7
|
root_file?: string;
|
|
17
8
|
/** Total number of files extracted */
|
|
18
9
|
file_count: number;
|
|
@@ -29,17 +20,6 @@ export declare function extractZipContentStream(zipBuffer: Buffer): AsyncGenerat
|
|
|
29
20
|
* @returns A dictionary containing the content of the zip file
|
|
30
21
|
*/
|
|
31
22
|
export declare function zipToDict(zipBuffer: Buffer): Promise<Record<string, string | Buffer>>;
|
|
32
|
-
/**
|
|
33
|
-
* Analyzes a tileset ZIP content and extracts metadata
|
|
34
|
-
* @param zipDict - Dictionary of files from zipToDict()
|
|
35
|
-
* @returns Tileset metadata including name and file structure
|
|
36
|
-
*/
|
|
37
|
-
export declare function analyzeTilesetContent(zipDict: Record<string, string | Buffer>): {
|
|
38
|
-
name: string;
|
|
39
|
-
fileCount: number;
|
|
40
|
-
hasMetadata: boolean;
|
|
41
|
-
mainFiles: string[];
|
|
42
|
-
};
|
|
43
23
|
/**
|
|
44
24
|
* Detects the root file for 3D Tiles tilesets
|
|
45
25
|
* Looks for tileset.json or similar entry point files
|
|
@@ -51,7 +31,7 @@ export declare function detectTilesetRootFile(files: string[]): string | undefin
|
|
|
51
31
|
* Normalizes file paths from ZIP archives
|
|
52
32
|
* Removes leading directory if all files share the same root folder
|
|
53
33
|
* @param files - Original file paths from the archive
|
|
54
|
-
* @returns Normalized file paths
|
|
34
|
+
* @returns Normalized file paths (original -> normalized)
|
|
55
35
|
*/
|
|
56
36
|
export declare function normalizeArchivePaths(files: string[]): Map<string, string>;
|
|
57
37
|
/**
|
|
@@ -61,21 +41,25 @@ export declare function normalizeArchivePaths(files: string[]): Map<string, stri
|
|
|
61
41
|
* 1. Extracts all files from the ZIP
|
|
62
42
|
* 2. Normalizes paths (removes common root directory if present)
|
|
63
43
|
* 3. Stores each file using the storage service with a unique base path
|
|
64
|
-
* 4. Returns
|
|
44
|
+
* 4. Returns the root file path and file count
|
|
45
|
+
*
|
|
46
|
+
* Files are uploaded in parallel batches for performance.
|
|
65
47
|
*
|
|
66
48
|
* @param zipBuffer - The ZIP file content as a Buffer
|
|
67
49
|
* @param storage - The storage service to use for saving files
|
|
68
|
-
* @param basePath - Base path/folder for storing extracted files (e.g., '
|
|
69
|
-
* @returns ExtractedArchiveResult with file
|
|
50
|
+
* @param basePath - Base path/folder for storing extracted files (e.g., 'tilesets/1234567890')
|
|
51
|
+
* @returns ExtractedArchiveResult with root file and file count
|
|
70
52
|
*
|
|
71
53
|
* @example
|
|
72
54
|
* ```typescript
|
|
73
|
-
* const result = await extractAndStoreArchive(zipBuffer, storage, '
|
|
74
|
-
* // result.files = [
|
|
75
|
-
* // { path: 'tilesets_manager/123/tileset.json', name: 'tileset.json', size: 1024 },
|
|
76
|
-
* // { path: 'tilesets_manager/123/tiles/tile_0.b3dm', name: 'tiles/tile_0.b3dm', size: 50000 }
|
|
77
|
-
* // ]
|
|
55
|
+
* const result = await extractAndStoreArchive(zipBuffer, storage, 'tilesets/1234567890')
|
|
78
56
|
* // result.root_file = 'tileset.json'
|
|
57
|
+
* // result.file_count = 42
|
|
58
|
+
*
|
|
59
|
+
* // Files are stored at:
|
|
60
|
+
* // tilesets/1234567890/tileset.json
|
|
61
|
+
* // tilesets/1234567890/tiles/tile_0.b3dm
|
|
62
|
+
* // etc.
|
|
79
63
|
* ```
|
|
80
64
|
*/
|
|
81
65
|
export declare function extractAndStoreArchive(zipBuffer: Buffer, storage: StorageService, basePath: string): Promise<ExtractedArchiveResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zip_utils.d.ts","sourceRoot":"","sources":["../../src/utils/zip_utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEnE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,
|
|
1
|
+
{"version":3,"file":"zip_utils.d.ts","sourceRoot":"","sources":["../../src/utils/zip_utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEnE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,wBAAuB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAqB3G;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAQ3F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAezE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAiB1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,sBAAsB,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,CAuEjC"}
|
package/dist/utils/zip_utils.js
CHANGED
|
@@ -37,43 +37,6 @@ export async function zipToDict(zipBuffer) {
|
|
|
37
37
|
}
|
|
38
38
|
return output;
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Analyzes a tileset ZIP content and extracts metadata
|
|
42
|
-
* @param zipDict - Dictionary of files from zipToDict()
|
|
43
|
-
* @returns Tileset metadata including name and file structure
|
|
44
|
-
*/
|
|
45
|
-
export function analyzeTilesetContent(zipDict) {
|
|
46
|
-
const files = Object.keys(zipDict);
|
|
47
|
-
const mainFiles = files.filter(f => f.endsWith('.json') || f.endsWith('.xml') || f.endsWith('.txt') || f.includes('metadata'));
|
|
48
|
-
// Try to extract tileset name from common patterns
|
|
49
|
-
let name = 'tileset';
|
|
50
|
-
const metadataFile = files.find(f => f.toLowerCase().includes('metadata'));
|
|
51
|
-
if (metadataFile && typeof zipDict[metadataFile] === 'string') {
|
|
52
|
-
try {
|
|
53
|
-
const metadata = JSON.parse(zipDict[metadataFile]);
|
|
54
|
-
name = metadata.name || metadata.title || name;
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
// Ignore parsing errors
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// Fallback: use first directory name or first file prefix
|
|
61
|
-
if (name === 'tileset') {
|
|
62
|
-
const firstFile = files[0];
|
|
63
|
-
if (firstFile && firstFile.includes('/')) {
|
|
64
|
-
name = firstFile.split('/')[0];
|
|
65
|
-
}
|
|
66
|
-
else if (firstFile && firstFile.includes('.')) {
|
|
67
|
-
name = firstFile.split('.')[0];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
name,
|
|
72
|
-
fileCount: files.length,
|
|
73
|
-
hasMetadata: mainFiles.length > 0,
|
|
74
|
-
mainFiles
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
40
|
/**
|
|
78
41
|
* Detects the root file for 3D Tiles tilesets
|
|
79
42
|
* Looks for tileset.json or similar entry point files
|
|
@@ -99,7 +62,7 @@ export function detectTilesetRootFile(files) {
|
|
|
99
62
|
* Normalizes file paths from ZIP archives
|
|
100
63
|
* Removes leading directory if all files share the same root folder
|
|
101
64
|
* @param files - Original file paths from the archive
|
|
102
|
-
* @returns Normalized file paths
|
|
65
|
+
* @returns Normalized file paths (original -> normalized)
|
|
103
66
|
*/
|
|
104
67
|
export function normalizeArchivePaths(files) {
|
|
105
68
|
const pathMap = new Map();
|
|
@@ -124,21 +87,25 @@ export function normalizeArchivePaths(files) {
|
|
|
124
87
|
* 1. Extracts all files from the ZIP
|
|
125
88
|
* 2. Normalizes paths (removes common root directory if present)
|
|
126
89
|
* 3. Stores each file using the storage service with a unique base path
|
|
127
|
-
* 4. Returns
|
|
90
|
+
* 4. Returns the root file path and file count
|
|
91
|
+
*
|
|
92
|
+
* Files are uploaded in parallel batches for performance.
|
|
128
93
|
*
|
|
129
94
|
* @param zipBuffer - The ZIP file content as a Buffer
|
|
130
95
|
* @param storage - The storage service to use for saving files
|
|
131
|
-
* @param basePath - Base path/folder for storing extracted files (e.g., '
|
|
132
|
-
* @returns ExtractedArchiveResult with file
|
|
96
|
+
* @param basePath - Base path/folder for storing extracted files (e.g., 'tilesets/1234567890')
|
|
97
|
+
* @returns ExtractedArchiveResult with root file and file count
|
|
133
98
|
*
|
|
134
99
|
* @example
|
|
135
100
|
* ```typescript
|
|
136
|
-
* const result = await extractAndStoreArchive(zipBuffer, storage, '
|
|
137
|
-
* // result.files = [
|
|
138
|
-
* // { path: 'tilesets_manager/123/tileset.json', name: 'tileset.json', size: 1024 },
|
|
139
|
-
* // { path: 'tilesets_manager/123/tiles/tile_0.b3dm', name: 'tiles/tile_0.b3dm', size: 50000 }
|
|
140
|
-
* // ]
|
|
101
|
+
* const result = await extractAndStoreArchive(zipBuffer, storage, 'tilesets/1234567890')
|
|
141
102
|
* // result.root_file = 'tileset.json'
|
|
103
|
+
* // result.file_count = 42
|
|
104
|
+
*
|
|
105
|
+
* // Files are stored at:
|
|
106
|
+
* // tilesets/1234567890/tileset.json
|
|
107
|
+
* // tilesets/1234567890/tiles/tile_0.b3dm
|
|
108
|
+
* // etc.
|
|
142
109
|
* ```
|
|
143
110
|
*/
|
|
144
111
|
export async function extractAndStoreArchive(zipBuffer, storage, basePath) {
|
|
@@ -150,14 +117,15 @@ export async function extractAndStoreArchive(zipBuffer, storage, basePath) {
|
|
|
150
117
|
.map(([name]) => name);
|
|
151
118
|
// Normalize paths (remove common root if present)
|
|
152
119
|
const normalizedPaths = normalizeArchivePaths(filePaths);
|
|
153
|
-
// Detect root file before normalization
|
|
120
|
+
// Detect root file before normalization, then get normalized path
|
|
154
121
|
const rootFileOriginal = detectTilesetRootFile(filePaths);
|
|
155
122
|
const rootFileNormalized = rootFileOriginal ? normalizedPaths.get(rootFileOriginal) : undefined;
|
|
156
|
-
|
|
157
|
-
// Extract and store files in parallel (batched to avoid overwhelming OVH)
|
|
123
|
+
// Extract and store files in parallel (batched to avoid overwhelming storage)
|
|
158
124
|
const PARALLEL_UPLOADS = 10;
|
|
159
125
|
const entries = Array.from(normalizedPaths.entries());
|
|
160
126
|
const totalFiles = entries.length;
|
|
127
|
+
let uploadedCount = 0;
|
|
128
|
+
const uploadedPaths = [];
|
|
161
129
|
console.log(`[ZipUtils] Extracting ${totalFiles} files to ${basePath}`);
|
|
162
130
|
try {
|
|
163
131
|
const totalBatches = Math.ceil(totalFiles / PARALLEL_UPLOADS);
|
|
@@ -166,32 +134,27 @@ export async function extractAndStoreArchive(zipBuffer, storage, basePath) {
|
|
|
166
134
|
for (let i = 0; i < entries.length; i += PARALLEL_UPLOADS) {
|
|
167
135
|
const batch = entries.slice(i, i + PARALLEL_UPLOADS);
|
|
168
136
|
const batchNum = Math.floor(i / PARALLEL_UPLOADS) + 1;
|
|
169
|
-
|
|
137
|
+
await Promise.all(batch.map(async ([originalPath, normalizedPath]) => {
|
|
170
138
|
const zipObject = zipContent.files[originalPath];
|
|
171
139
|
const content = await zipObject.async('nodebuffer');
|
|
172
140
|
// Build storage path: basePath/normalizedPath
|
|
173
141
|
const storagePath = `${basePath}/${normalizedPath}`;
|
|
174
142
|
// Save the file using saveWithPath which preserves the exact path
|
|
175
143
|
await storage.saveWithPath(content, storagePath);
|
|
176
|
-
|
|
177
|
-
path: storagePath,
|
|
178
|
-
name: normalizedPath,
|
|
179
|
-
size: content.length
|
|
180
|
-
};
|
|
144
|
+
uploadedPaths.push(storagePath);
|
|
181
145
|
}));
|
|
182
|
-
|
|
146
|
+
uploadedCount += batch.length;
|
|
183
147
|
// Log progress periodically (every ~10%) or on last batch
|
|
184
148
|
if (batchNum % logInterval === 0 || batchNum === totalBatches) {
|
|
185
|
-
const percent = Math.round((
|
|
186
|
-
console.log(`[ZipUtils] Progress: ${percent}% (${
|
|
149
|
+
const percent = Math.round((uploadedCount / totalFiles) * 100);
|
|
150
|
+
console.log(`[ZipUtils] Progress: ${percent}% (${uploadedCount}/${totalFiles} files)`);
|
|
187
151
|
}
|
|
188
152
|
}
|
|
189
153
|
}
|
|
190
154
|
catch (error) {
|
|
191
155
|
// Clean up any files that were already uploaded before the error
|
|
192
|
-
if (
|
|
193
|
-
console.log(`[ZipUtils] Error during extraction, cleaning up ${
|
|
194
|
-
const uploadedPaths = storedFiles.map(f => f.path);
|
|
156
|
+
if (uploadedPaths.length > 0) {
|
|
157
|
+
console.log(`[ZipUtils] Error during extraction, cleaning up ${uploadedPaths.length} uploaded files...`);
|
|
195
158
|
await storage.deleteBatch(uploadedPaths).catch(cleanupErr => {
|
|
196
159
|
console.error(`[ZipUtils] Failed to clean up files after error:`, cleanupErr);
|
|
197
160
|
});
|
|
@@ -199,9 +162,8 @@ export async function extractAndStoreArchive(zipBuffer, storage, basePath) {
|
|
|
199
162
|
throw error;
|
|
200
163
|
}
|
|
201
164
|
return {
|
|
202
|
-
files: storedFiles,
|
|
203
165
|
root_file: rootFileNormalized,
|
|
204
|
-
file_count:
|
|
166
|
+
file_count: uploadedCount
|
|
205
167
|
};
|
|
206
168
|
}
|
|
207
169
|
//# sourceMappingURL=zip_utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zip_utils.js","sourceRoot":"","sources":["../../src/utils/zip_utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"zip_utils.js","sourceRoot":"","sources":["../../src/utils/zip_utils.ts"],"names":[],"mappings":"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"}
|