@twin.org/blob-storage-service 0.0.1-next.9 → 0.0.2-next.1

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.
@@ -1,11 +1,16 @@
1
- import { StringHelper, Guards, ComponentFactory, Is, Converter, GeneralError, Validation, ObjectHelper, Urn, NotFoundError } from '@twin.org/core';
1
+ import { HttpParameterHelper } from '@twin.org/api-models';
2
+ import { BlobStorageTypes, BlobStorageContexts, BlobStorageCompressionType, BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
3
+ import { StringHelper, Guards, ComponentFactory, Coerce, Is, Converter, GeneralError, Validation, Compression, ObjectHelper, Urn, NotFoundError } from '@twin.org/core';
4
+ import { SchemaOrgContexts, SchemaOrgTypes, SchemaOrgDataTypes } from '@twin.org/standards-schema-org';
2
5
  import { HttpStatusCode, HeaderTypes, MimeTypes, MimeTypeHelper } from '@twin.org/web';
3
- import { BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
4
- import { JsonLdHelper } from '@twin.org/data-json-ld';
5
- import { ComparisonOperator, EntitySchemaHelper, LogicalOperator, property, entity, EntitySchemaFactory } from '@twin.org/entity';
6
+ import { Sha256 } from '@twin.org/crypto';
7
+ import { JsonLdHelper, JsonLdProcessor } from '@twin.org/data-json-ld';
8
+ import { ComparisonOperator, LogicalOperator, SortDirection, EntitySchemaHelper, property, entity, EntitySchemaFactory } from '@twin.org/entity';
6
9
  import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
7
10
  import { VaultConnectorFactory, VaultEncryptionType } from '@twin.org/vault-models';
8
11
 
12
+ // Copyright 2024 IOTA Stiftung.
13
+ // SPDX-License-Identifier: Apache-2.0.
9
14
  /**
10
15
  * The source used when communicating about these routes.
11
16
  */
@@ -48,7 +53,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
48
53
  body: {
49
54
  blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==",
50
55
  metadata: {
51
- "@context": "http://schema.org/",
56
+ "@context": "https://schema.org",
52
57
  "@type": "DigitalDocument",
53
58
  name: "myfile.pdf"
54
59
  }
@@ -91,7 +96,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
91
96
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
92
97
  },
93
98
  query: {
94
- includeContent: true
99
+ includeContent: "true"
95
100
  }
96
101
  }
97
102
  }
@@ -105,8 +110,51 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
105
110
  id: `${camelTypeName}GetResponseExample`,
106
111
  response: {
107
112
  body: {
113
+ "@context": [
114
+ BlobStorageContexts.ContextRoot,
115
+ BlobStorageContexts.ContextRootCommon,
116
+ SchemaOrgContexts.ContextRoot
117
+ ],
118
+ type: BlobStorageTypes.Entry,
119
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
120
+ dateCreated: "2024-01-01T00:00:00Z",
121
+ encodingFormat: MimeTypes.Pdf,
122
+ blobSize: 42,
123
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
124
+ fileExtension: "pdf",
125
+ metadata: {
126
+ "@context": "https://schema.org",
127
+ "@type": "DigitalDocument",
128
+ name: "myfile.pdf"
129
+ },
130
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
131
+ }
132
+ }
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ type: "IBlobStorageGetResponse",
138
+ mimeType: MimeTypes.JsonLd,
139
+ examples: [
140
+ {
141
+ id: `${camelTypeName}GetResponseJsonLdExample`,
142
+ response: {
143
+ body: {
144
+ "@context": [
145
+ BlobStorageContexts.ContextRoot,
146
+ BlobStorageContexts.ContextRootCommon,
147
+ SchemaOrgContexts.ContextRoot
148
+ ],
149
+ type: BlobStorageTypes.Entry,
150
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
151
+ dateCreated: "2024-01-01T00:00:00Z",
152
+ encodingFormat: MimeTypes.Pdf,
153
+ blobSize: 42,
154
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
155
+ fileExtension: "pdf",
108
156
  metadata: {
109
- "@context": "http://schema.org/",
157
+ "@context": "https://schema.org",
110
158
  "@type": "DigitalDocument",
111
159
  name: "myfile.pdf"
112
160
  },
@@ -138,7 +186,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
138
186
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
139
187
  },
140
188
  query: {
141
- download: true,
189
+ download: "true",
142
190
  filename: "my-file.pdf"
143
191
  }
144
192
  }
@@ -152,7 +200,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
152
200
  examples: [
153
201
  {
154
202
  id: `${camelTypeName}GetContentResponseExample`,
155
- description: `The content of the blob, which will be a specific mime type if one can be detected from the content (or set as mimeType in the metadata), or defaults to ${MimeTypes.OctetStream}.`,
203
+ description: `The content of the blob, which will be a specific mime type if one can be detected from the content (or set as encodingFormat in the entry), or defaults to ${MimeTypes.OctetStream}.`,
156
204
  response: {
157
205
  body: new Uint8Array()
158
206
  }
@@ -182,7 +230,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
182
230
  },
183
231
  body: {
184
232
  metadata: {
185
- "@context": "http://schema.org/",
233
+ "@context": "https://schema.org",
186
234
  "@type": "DigitalDocument",
187
235
  name: "myfile.pdf"
188
236
  }
@@ -226,12 +274,116 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
226
274
  }
227
275
  ]
228
276
  };
277
+ const blobStorageListRoute = {
278
+ operationId: `${camelTypeName}Query`,
279
+ summary: `Query the items from ${lowerName}`,
280
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
281
+ method: "GET",
282
+ path: `${baseRouteName}/`,
283
+ handler: async (httpRequestContext, request) => blobStorageList(httpRequestContext, componentName, request),
284
+ requestType: {
285
+ type: "IBlobStorageListRequest",
286
+ examples: [
287
+ {
288
+ id: `${camelTypeName}ListRequestExample`,
289
+ request: {}
290
+ }
291
+ ]
292
+ },
293
+ responseType: [
294
+ {
295
+ type: "IBlobStorageListResponse",
296
+ examples: [
297
+ {
298
+ id: `${camelTypeName}ListResponseExample`,
299
+ response: {
300
+ body: {
301
+ "@context": [
302
+ SchemaOrgContexts.ContextRoot,
303
+ BlobStorageContexts.ContextRoot,
304
+ BlobStorageContexts.ContextRootCommon
305
+ ],
306
+ type: SchemaOrgTypes.ItemList,
307
+ [SchemaOrgTypes.ItemListElement]: [
308
+ {
309
+ "@context": [
310
+ BlobStorageContexts.ContextRoot,
311
+ BlobStorageContexts.ContextRootCommon,
312
+ SchemaOrgContexts.ContextRoot
313
+ ],
314
+ type: BlobStorageTypes.Entry,
315
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
316
+ dateCreated: "2024-01-01T00:00:00Z",
317
+ encodingFormat: MimeTypes.Pdf,
318
+ blobSize: 42,
319
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
320
+ fileExtension: "pdf",
321
+ metadata: {
322
+ "@context": "https://schema.org",
323
+ "@type": "DigitalDocument",
324
+ name: "myfile.pdf"
325
+ },
326
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
327
+ }
328
+ ]
329
+ }
330
+ }
331
+ }
332
+ ]
333
+ },
334
+ {
335
+ type: "IBlobStorageListResponse",
336
+ mimeType: MimeTypes.JsonLd,
337
+ examples: [
338
+ {
339
+ id: `${camelTypeName}ListResponseJsonLdExample`,
340
+ response: {
341
+ body: {
342
+ "@context": [
343
+ SchemaOrgContexts.ContextRoot,
344
+ BlobStorageContexts.ContextRoot,
345
+ BlobStorageContexts.ContextRootCommon
346
+ ],
347
+ type: SchemaOrgTypes.ItemList,
348
+ [SchemaOrgTypes.ItemListElement]: [
349
+ {
350
+ "@context": [
351
+ BlobStorageContexts.ContextRoot,
352
+ BlobStorageContexts.ContextRootCommon,
353
+ SchemaOrgContexts.ContextRoot
354
+ ],
355
+ type: BlobStorageTypes.Entry,
356
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
357
+ dateCreated: "2024-01-01T00:00:00Z",
358
+ encodingFormat: MimeTypes.Pdf,
359
+ blobSize: 42,
360
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
361
+ fileExtension: "pdf",
362
+ metadata: {
363
+ "@context": "https://schema.org",
364
+ "@type": "DigitalDocument",
365
+ name: "myfile.pdf"
366
+ },
367
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
368
+ }
369
+ ]
370
+ }
371
+ }
372
+ }
373
+ ]
374
+ },
375
+ {
376
+ type: "INotFoundResponse"
377
+ }
378
+ ]
379
+ };
229
380
  return [
230
381
  blobStorageCreateRoute,
231
382
  blobStorageGetRoute,
232
383
  blobStorageGetContentRoute,
233
384
  blobStorageUpdateRoute,
234
- blobStorageRemoveRoute
385
+ blobStorageRemoveRoute,
386
+ blobStorageListRoute
235
387
  ];
236
388
  }
237
389
  /**
@@ -246,7 +398,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
246
398
  Guards.object(ROUTES_SOURCE, "request.body", request.body);
247
399
  Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
248
400
  const component = ComponentFactory.get(componentName);
249
- const id = await component.create(request.body.blob, request.body.mimeType, request.body.extension, request.body.metadata, request.body.namespace, httpRequestContext.nodeIdentity);
401
+ const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, {
402
+ disableEncryption: request.body.disableEncryption,
403
+ overrideVaultKeyId: request.body.overrideVaultKeyId,
404
+ namespace: request.body.namespace
405
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
250
406
  return {
251
407
  statusCode: HttpStatusCode.created,
252
408
  headers: {
@@ -265,9 +421,17 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
265
421
  Guards.object(ROUTES_SOURCE, "request", request);
266
422
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
267
423
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
424
+ const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
268
425
  const component = ComponentFactory.get(componentName);
269
- const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
426
+ const result = await component.get(request.pathParams.id, {
427
+ includeContent: Coerce.boolean(request.query?.includeContent),
428
+ decompress: Coerce.boolean(request.query?.decompress),
429
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
430
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
270
431
  return {
432
+ headers: {
433
+ [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
434
+ },
271
435
  body: result
272
436
  };
273
437
  }
@@ -283,18 +447,34 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
283
447
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
284
448
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
285
449
  const component = ComponentFactory.get(componentName);
286
- const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
287
- const mimeType = result?.mimeType ?? MimeTypes.OctetStream;
450
+ const decompress = Coerce.boolean(request.query?.decompress);
451
+ const download = Coerce.boolean(request.query?.download) ?? false;
452
+ const result = await component.get(request.pathParams.id, {
453
+ includeContent: true,
454
+ decompress,
455
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
456
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
457
+ const encodingFormat = result?.encodingFormat ?? MimeTypes.OctetStream;
458
+ let compressedEncodingFormat;
459
+ let compressedExtension = "";
460
+ // If the entry is compressed and we are not decompressing
461
+ // we need to override the encoding format to the compressed type
462
+ // and append an additional extension to the filename.
463
+ if (result.compression && !decompress) {
464
+ compressedEncodingFormat =
465
+ result.compression === BlobStorageCompressionType.Gzip ? MimeTypes.Gzip : MimeTypes.Zlib;
466
+ compressedExtension = `.${MimeTypeHelper.defaultExtension(compressedEncodingFormat)}`;
467
+ }
288
468
  let filename = request.query?.filename;
289
469
  if (!Is.stringValue(filename)) {
290
- filename = `file.${result.extension ?? MimeTypeHelper.defaultExtension(mimeType)}`;
470
+ filename = `file.${result.fileExtension ?? MimeTypeHelper.defaultExtension(encodingFormat)}${compressedExtension}`;
291
471
  }
292
472
  return {
293
473
  body: Is.stringBase64(result.blob) ? Converter.base64ToBytes(result.blob) : new Uint8Array(),
294
474
  attachment: {
295
- mimeType,
475
+ mimeType: compressedEncodingFormat ?? encodingFormat,
296
476
  filename,
297
- inline: !(request.query?.download ?? false)
477
+ inline: !download
298
478
  }
299
479
  };
300
480
  }
@@ -310,7 +490,7 @@ async function blobStorageUpdate(httpRequestContext, componentName, request) {
310
490
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
311
491
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
312
492
  const component = ComponentFactory.get(componentName);
313
- await component.update(request.pathParams.id, request.body.mimeType, request.body.extension, request.body.metadata, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
493
+ await component.update(request.pathParams.id, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, httpRequestContext.userIdentity);
314
494
  return {
315
495
  statusCode: HttpStatusCode.noContent
316
496
  };
@@ -327,11 +507,30 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
327
507
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
328
508
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
329
509
  const component = ComponentFactory.get(componentName);
330
- await component.remove(request.pathParams.id, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
510
+ await component.remove(request.pathParams.id, httpRequestContext.userIdentity);
331
511
  return {
332
512
  statusCode: HttpStatusCode.noContent
333
513
  };
334
514
  }
515
+ /**
516
+ * List the entries from blob storage.
517
+ * @param httpRequestContext The request context for the API.
518
+ * @param componentName The name of the component to use in the routes.
519
+ * @param request The request.
520
+ * @returns The response object with additional http response properties.
521
+ */
522
+ async function blobStorageList(httpRequestContext, componentName, request) {
523
+ Guards.object(ROUTES_SOURCE, "request", request);
524
+ const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
525
+ const component = ComponentFactory.get(componentName);
526
+ const result = await component.query(HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, Coerce.number(request.query?.pageSize), httpRequestContext.userIdentity);
527
+ return {
528
+ headers: {
529
+ [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
530
+ },
531
+ body: result
532
+ };
533
+ }
335
534
 
336
535
  // Copyright 2024 IOTA Stiftung.
337
536
  // SPDX-License-Identifier: Apache-2.0.
@@ -341,8 +540,9 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
341
540
  class BlobStorageService {
342
541
  /**
343
542
  * The namespace supported by the blob storage service.
543
+ * @internal
344
544
  */
345
- static NAMESPACE = "blob";
545
+ static _NAMESPACE = "blob";
346
546
  /**
347
547
  * Runtime name for the class.
348
548
  */
@@ -357,7 +557,7 @@ class BlobStorageService {
357
557
  * The storage connector for the metadata.
358
558
  * @internal
359
559
  */
360
- _metadataEntityStorage;
560
+ _entryEntityStorage;
361
561
  /**
362
562
  * The vault connector for the encryption, can be undefined if no encryption required.
363
563
  * @internal
@@ -369,97 +569,103 @@ class BlobStorageService {
369
569
  */
370
570
  _vaultKeyId;
371
571
  /**
372
- * Include the node identity when performing storage operations, defaults to true.
572
+ * Include the user identity when performing storage operations, can be used to partition for users, defaults to false.
373
573
  * @internal
374
574
  */
375
- _includeNodeIdentity;
376
- /**
377
- * Include the user identity when performing storage operations, defaults to true.
378
- * @internal
379
- */
380
- _includeUserIdentity;
575
+ _partitionPerUser;
381
576
  /**
382
577
  * Create a new instance of BlobStorageService.
383
- * @param options The dependencies for the service.
384
- * @param options.metadataEntityStorageType The type of the storage connector for the metadata, defaults to "blob-metadata".
385
- * @param options.vaultConnectorType The type of the vault connector for encryption, if undefined no encryption will be performed.
386
- * @param options.config The configuration for the service.
578
+ * @param options The options for the service.
387
579
  */
388
580
  constructor(options) {
389
581
  const names = BlobStorageConnectorFactory.names();
390
582
  if (names.length === 0) {
391
583
  throw new GeneralError(this.CLASS_NAME, "noConnectors");
392
584
  }
393
- this._metadataEntityStorage = EntityStorageConnectorFactory.get(options?.metadataEntityStorageType ?? "blob-metadata");
585
+ this._entryEntityStorage = EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
394
586
  if (Is.stringValue(options?.vaultConnectorType)) {
395
- this._vaultConnector = VaultConnectorFactory.getIfExists(options.vaultConnectorType);
587
+ this._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType);
396
588
  }
397
589
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
398
- this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
399
- this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
400
- this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
590
+ this._vaultKeyId = options?.config?.vaultKeyId;
591
+ this._partitionPerUser = options?.config?.partitionPerUser ?? false;
592
+ SchemaOrgDataTypes.registerRedirects();
401
593
  }
402
594
  /**
403
595
  * Create the blob with some metadata.
404
596
  * @param blob The data for the blob in base64 format.
405
- * @param mimeType Mime type for the blob, will be detected if left undefined.
406
- * @param extension Extension for the blob, will be detected if left undefined.
597
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
598
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
407
599
  * @param metadata Data for the custom metadata as JSON-LD.
408
- * @param namespace The namespace to use for storing, defaults to component configured namespace.
600
+ * @param options Optional options for the creation of the blob.
601
+ * @param options.disableEncryption Disables encryption if enabled by default.
602
+ * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
603
+ * @param options.compress Optional compression type to use for the blob, defaults to no compression.*
604
+ * @param options.namespace The namespace to use for storing, defaults to component configured namespace.
409
605
  * @param userIdentity The user identity to use with storage operations.
410
606
  * @param nodeIdentity The node identity to use with storage operations.
411
607
  * @returns The id of the stored blob in urn format.
412
608
  */
413
- async create(blob, mimeType, extension, metadata, namespace, userIdentity, nodeIdentity) {
609
+ async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
414
610
  Guards.stringBase64(this.CLASS_NAME, "blob", blob);
415
- if (this._includeUserIdentity) {
611
+ if (this._partitionPerUser) {
416
612
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
417
613
  }
418
- if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
419
- Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
420
- }
614
+ const disableEncryption = options?.disableEncryption ?? false;
615
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
616
+ const encryptionEnabled = !disableEncryption && Is.stringValue(vaultKeyId);
421
617
  try {
422
- const connectorNamespace = namespace ?? this._defaultNamespace;
618
+ const connectorNamespace = options?.namespace ?? this._defaultNamespace;
423
619
  const blobStorageConnector = BlobStorageConnectorFactory.get(connectorNamespace);
424
620
  // Convert the base64 data into bytes
425
621
  let storeBlob = Converter.base64ToBytes(blob);
622
+ const blobSize = storeBlob.length;
426
623
  // See if we can detect the mime type and default extension for the data.
427
624
  // If not already supplied by the caller. We have to perform this operation
428
625
  // on the unencrypted data.
429
- if (!Is.stringValue(mimeType)) {
430
- mimeType = await MimeTypeHelper.detect(storeBlob);
626
+ if (!Is.stringValue(encodingFormat)) {
627
+ encodingFormat = await MimeTypeHelper.detect(storeBlob);
431
628
  }
432
- if (!Is.stringValue(extension) && Is.stringValue(mimeType)) {
433
- extension = await MimeTypeHelper.defaultExtension(mimeType);
629
+ if (!Is.stringValue(fileExtension) && Is.stringValue(encodingFormat)) {
630
+ fileExtension = await MimeTypeHelper.defaultExtension(encodingFormat);
434
631
  }
435
632
  if (Is.object(metadata)) {
436
633
  const validationFailures = [];
437
634
  JsonLdHelper.validate(metadata, validationFailures);
438
635
  Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
439
636
  }
637
+ const blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;
638
+ if (!Is.empty(options?.compress)) {
639
+ storeBlob = await Compression.compress(storeBlob, options.compress);
640
+ }
440
641
  // If we have a vault connector then encrypt the data.
441
- if (this._vaultConnector) {
442
- storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
642
+ if (encryptionEnabled) {
643
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
644
+ if (Is.empty(this._vaultConnector)) {
645
+ throw new GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
646
+ }
647
+ storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
443
648
  }
444
649
  // Set the blob in the storage connector, which may now be encrypted
445
650
  const blobId = await blobStorageConnector.set(storeBlob);
446
- // Now store the metadata in entity storage
447
- const blobMetadata = {
651
+ // Now store the entry in entity storage
652
+ const blobEntry = {
448
653
  id: blobId,
449
- mimeType,
450
- extension,
451
- metadata
654
+ dateCreated: new Date(Date.now()).toISOString(),
655
+ blobSize,
656
+ blobHash,
657
+ encodingFormat,
658
+ fileExtension,
659
+ metadata,
660
+ isEncrypted: encryptionEnabled,
661
+ compression: options?.compress
452
662
  };
453
663
  const conditions = [];
454
- if (this._includeUserIdentity) {
455
- ObjectHelper.propertySet(blobMetadata, "userIdentity", userIdentity);
664
+ if (this._partitionPerUser) {
665
+ ObjectHelper.propertySet(blobEntry, "userIdentity", userIdentity);
456
666
  conditions.push({ property: "userIdentity", value: userIdentity });
457
667
  }
458
- if (this._includeNodeIdentity) {
459
- ObjectHelper.propertySet(blobMetadata, "nodeIdentity", nodeIdentity);
460
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
461
- }
462
- await this._metadataEntityStorage.set(blobMetadata, conditions);
668
+ await this._entryEntityStorage.set(blobEntry, conditions);
463
669
  return blobId;
464
670
  }
465
671
  catch (error) {
@@ -467,18 +673,23 @@ class BlobStorageService {
467
673
  }
468
674
  }
469
675
  /**
470
- * Get the blob and metadata.
676
+ * Get the blob entry.
471
677
  * @param id The id of the blob to get in urn format.
472
- * @param includeContent Include the content, or just get the metadata.
678
+ * @param options Optional options for the retrieval of the blob.
679
+ * @param options.includeContent Include the content, or just get the metadata.
680
+ * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
681
+ * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
473
682
  * @param userIdentity The user identity to use with storage operations.
474
683
  * @param nodeIdentity The node identity to use with storage operations.
475
- * @returns The metadata and data for the blob if it can be found.
684
+ * @returns The entry and data for the blob if it can be found.
476
685
  * @throws Not found error if the blob cannot be found.
477
686
  */
478
- async get(id, includeContent, userIdentity, nodeIdentity) {
687
+ async get(id, options, userIdentity, nodeIdentity) {
479
688
  Urn.guard(this.CLASS_NAME, "id", id);
689
+ const includeContent = options?.includeContent ?? false;
690
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
480
691
  const conditions = [];
481
- if (this._includeUserIdentity) {
692
+ if (this._partitionPerUser) {
482
693
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
483
694
  conditions.push({
484
695
  property: "userIdentity",
@@ -486,16 +697,8 @@ class BlobStorageService {
486
697
  value: userIdentity
487
698
  });
488
699
  }
489
- if (this._includeNodeIdentity || (Is.notEmpty(this._vaultConnector) && includeContent)) {
490
- Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
491
- conditions.push({
492
- property: "nodeIdentity",
493
- comparison: ComparisonOperator.Equals,
494
- value: nodeIdentity
495
- });
496
- }
497
700
  try {
498
- const blobMetadata = await this.internalGet(id, userIdentity, nodeIdentity);
701
+ const blobEntry = await this.internalGet(id, userIdentity);
499
702
  let returnBlob;
500
703
  if (includeContent) {
501
704
  const blobStorageConnector = this.getConnector(id);
@@ -503,17 +706,21 @@ class BlobStorageService {
503
706
  if (Is.undefined(returnBlob)) {
504
707
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
505
708
  }
506
- // If we have a vault connector then decrypt the data.
507
- if (this._vaultConnector) {
508
- returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
709
+ // If the data is encrypted then decrypt it.
710
+ const decryptionEnabled = blobEntry.isEncrypted && Is.stringValue(vaultKeyId);
711
+ if (decryptionEnabled) {
712
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
713
+ if (Is.empty(this._vaultConnector)) {
714
+ throw new GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
715
+ }
716
+ returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
717
+ }
718
+ if (!Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {
719
+ returnBlob = await Compression.decompress(returnBlob, blobEntry.compression);
509
720
  }
510
721
  }
511
- return {
512
- blob: Is.uint8Array(returnBlob) ? Converter.bytesToBase64(returnBlob) : undefined,
513
- mimeType: blobMetadata?.mimeType,
514
- extension: blobMetadata?.extension,
515
- metadata: blobMetadata?.metadata
516
- };
722
+ const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
723
+ return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
517
724
  }
518
725
  catch (error) {
519
726
  throw new GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
@@ -521,26 +728,22 @@ class BlobStorageService {
521
728
  }
522
729
  /**
523
730
  * Update the blob with metadata.
524
- * @param id The id of the blob metadata to update.
525
- * @param mimeType Mime type for the blob, will be detected if left undefined.
526
- * @param extension Extension for the blob, will be detected if left undefined.
731
+ * @param id The id of the blob entry to update.
732
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
733
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
527
734
  * @param metadata Data for the custom metadata as JSON-LD.
528
735
  * @param userIdentity The user identity to use with storage operations.
529
- * @param nodeIdentity The node identity to use with storage operations.
530
736
  * @returns Nothing.
531
737
  * @throws Not found error if the blob cannot be found.
532
738
  */
533
- async update(id, mimeType, extension, metadata, userIdentity, nodeIdentity) {
739
+ async update(id, encodingFormat, fileExtension, metadata, userIdentity) {
534
740
  Urn.guard(this.CLASS_NAME, "id", id);
535
- if (this._includeUserIdentity) {
741
+ if (this._partitionPerUser) {
536
742
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
537
743
  }
538
- if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
539
- Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
540
- }
541
744
  try {
542
- const blobMetadata = await this._metadataEntityStorage.get(id);
543
- if (Is.undefined(blobMetadata)) {
745
+ const blobEntry = await this._entryEntityStorage.get(id);
746
+ if (Is.undefined(blobEntry)) {
544
747
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
545
748
  }
546
749
  if (Is.object(metadata)) {
@@ -548,23 +751,25 @@ class BlobStorageService {
548
751
  await JsonLdHelper.validate(metadata, validationFailures);
549
752
  Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
550
753
  }
551
- // Now store the metadata in entity storage
552
- const updatedBlobMetadata = {
553
- id: blobMetadata.id,
554
- mimeType: mimeType ?? blobMetadata.mimeType,
555
- extension: extension ?? blobMetadata.extension,
556
- metadata: metadata ?? blobMetadata.metadata
754
+ // Now store the entry in entity storage
755
+ const updatedBlobEntry = {
756
+ id: blobEntry.id,
757
+ dateCreated: blobEntry.dateCreated,
758
+ dateModified: new Date(Date.now()).toISOString(),
759
+ blobSize: blobEntry.blobSize,
760
+ blobHash: blobEntry.blobHash,
761
+ encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
762
+ fileExtension: fileExtension ?? blobEntry.fileExtension,
763
+ metadata: metadata ?? blobEntry.metadata,
764
+ isEncrypted: blobEntry.isEncrypted,
765
+ compression: blobEntry.compression
557
766
  };
558
767
  const conditions = [];
559
- if (this._includeUserIdentity) {
560
- ObjectHelper.propertySet(updatedBlobMetadata, "userIdentity", userIdentity);
768
+ if (this._partitionPerUser) {
769
+ ObjectHelper.propertySet(updatedBlobEntry, "userIdentity", userIdentity);
561
770
  conditions.push({ property: "userIdentity", value: userIdentity });
562
771
  }
563
- if (this._includeNodeIdentity) {
564
- ObjectHelper.propertySet(updatedBlobMetadata, "nodeIdentity", nodeIdentity);
565
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
566
- }
567
- await this._metadataEntityStorage.set(updatedBlobMetadata, conditions);
772
+ await this._entryEntityStorage.set(updatedBlobEntry, conditions);
568
773
  }
569
774
  catch (error) {
570
775
  throw new GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
@@ -574,27 +779,20 @@ class BlobStorageService {
574
779
  * Remove the blob.
575
780
  * @param id The id of the blob to remove in urn format.
576
781
  * @param userIdentity The user identity to use with storage operations.
577
- * @param nodeIdentity The node identity to use with storage operations.
578
782
  * @returns Nothing.
579
783
  */
580
- async remove(id, userIdentity, nodeIdentity) {
784
+ async remove(id, userIdentity) {
581
785
  Urn.guard(this.CLASS_NAME, "id", id);
582
- if (this._includeUserIdentity) {
786
+ if (this._partitionPerUser) {
583
787
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
584
788
  }
585
- if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
586
- Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
587
- }
588
789
  try {
589
790
  const blobStorageConnector = this.getConnector(id);
590
791
  const conditions = [];
591
- if (this._includeUserIdentity) {
792
+ if (this._partitionPerUser) {
592
793
  conditions.push({ property: "userIdentity", value: userIdentity });
593
794
  }
594
- if (this._includeNodeIdentity) {
595
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
596
- }
597
- await this._metadataEntityStorage.remove(id, conditions);
795
+ await this._entryEntityStorage.remove(id, conditions);
598
796
  const removed = await blobStorageConnector.remove(id);
599
797
  if (!removed) {
600
798
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
@@ -604,6 +802,60 @@ class BlobStorageService {
604
802
  throw new GeneralError(this.CLASS_NAME, "removeFailed", undefined, error);
605
803
  }
606
804
  }
805
+ /**
806
+ * Query all the blob storage entries which match the conditions.
807
+ * @param conditions The conditions to match for the entries.
808
+ * @param orderBy The order for the results, defaults to created.
809
+ * @param orderByDirection The direction for the order, defaults to descending.
810
+ * @param cursor The cursor to request the next page of entries.
811
+ * @param pageSize The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
812
+ * @param userIdentity The user identity to use with storage operations.
813
+ * @returns All the entries for the storage matching the conditions,
814
+ * and a cursor which can be used to request more entities.
815
+ */
816
+ async query(conditions, orderBy, orderByDirection, cursor, pageSize, userIdentity) {
817
+ const finalConditions = {
818
+ conditions: [],
819
+ logicalOperator: LogicalOperator.And
820
+ };
821
+ if (this._partitionPerUser) {
822
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
823
+ finalConditions.conditions.push({
824
+ property: "userIdentity",
825
+ comparison: ComparisonOperator.Equals,
826
+ value: userIdentity
827
+ });
828
+ }
829
+ if (!Is.empty(conditions)) {
830
+ finalConditions.conditions.push(conditions);
831
+ }
832
+ const orderProperty = orderBy ?? "dateCreated";
833
+ const orderDirection = orderByDirection ?? SortDirection.Descending;
834
+ const result = await this._entryEntityStorage.query(finalConditions.conditions.length > 0 ? finalConditions : undefined, [
835
+ {
836
+ property: orderProperty,
837
+ sortDirection: orderDirection
838
+ }
839
+ ], undefined, cursor, pageSize);
840
+ let context = [
841
+ SchemaOrgContexts.ContextRoot,
842
+ BlobStorageContexts.ContextRoot,
843
+ BlobStorageContexts.ContextRootCommon
844
+ ];
845
+ const entriesJsonLd = [];
846
+ for (const entry of result.entities) {
847
+ // The entries are never Partial as we don't allow custom property requests.
848
+ entriesJsonLd.push(this.entryToJsonLd(entry));
849
+ context = JsonLdProcessor.combineContexts(context, entry.metadata?.["@context"]);
850
+ }
851
+ const jsonLd = {
852
+ "@context": context,
853
+ type: SchemaOrgTypes.ItemList,
854
+ [SchemaOrgTypes.ItemListElement]: entriesJsonLd,
855
+ [SchemaOrgTypes.NextItem]: result.cursor
856
+ };
857
+ return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
858
+ }
607
859
  /**
608
860
  * Get the connector from the uri.
609
861
  * @param id The id of the blob storage item in urn format.
@@ -612,9 +864,9 @@ class BlobStorageService {
612
864
  */
613
865
  getConnector(id) {
614
866
  const idUri = Urn.fromValidString(id);
615
- if (idUri.namespaceIdentifier() !== BlobStorageService.NAMESPACE) {
867
+ if (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {
616
868
  throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
617
- namespace: BlobStorageService.NAMESPACE,
869
+ namespace: BlobStorageService._NAMESPACE,
618
870
  id
619
871
  });
620
872
  }
@@ -625,13 +877,12 @@ class BlobStorageService {
625
877
  * @param id The id of the entity to get, or the index value if secondaryIndex is set.
626
878
  * @param secondaryIndex Get the item using a secondary index.
627
879
  * @param userIdentity The user identity to use with storage operations.
628
- * @param nodeIdentity The node identity to use with storage operations.
629
880
  * @returns The object if it can be found or throws.
630
881
  * @internal
631
882
  */
632
- async internalGet(id, userIdentity, nodeIdentity) {
883
+ async internalGet(id, userIdentity) {
633
884
  const conditions = [];
634
- if (this._includeUserIdentity) {
885
+ if (this._partitionPerUser) {
635
886
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
636
887
  conditions.push({
637
888
  property: "userIdentity",
@@ -639,27 +890,19 @@ class BlobStorageService {
639
890
  value: userIdentity
640
891
  });
641
892
  }
642
- if (this._includeNodeIdentity) {
643
- Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
644
- conditions.push({
645
- property: "nodeIdentity",
646
- comparison: ComparisonOperator.Equals,
647
- value: nodeIdentity
648
- });
649
- }
650
893
  let entity;
651
894
  if (conditions.length === 0) {
652
- entity = await this._metadataEntityStorage.get(id);
895
+ entity = await this._entryEntityStorage.get(id);
653
896
  }
654
897
  else {
655
- const schema = this._metadataEntityStorage.getSchema();
898
+ const schema = this._entryEntityStorage.getSchema();
656
899
  const primaryKey = EntitySchemaHelper.getPrimaryKey(schema);
657
900
  conditions.unshift({
658
901
  property: primaryKey.property,
659
902
  comparison: ComparisonOperator.Equals,
660
903
  value: id
661
904
  });
662
- const results = await this._metadataEntityStorage.query({
905
+ const results = await this._entryEntityStorage.query({
663
906
  conditions,
664
907
  logicalOperator: LogicalOperator.And
665
908
  }, undefined, undefined, undefined, 1);
@@ -668,68 +911,140 @@ class BlobStorageService {
668
911
  if (Is.empty(entity)) {
669
912
  throw new NotFoundError(this.CLASS_NAME, "entityNotFound", id);
670
913
  }
671
- ObjectHelper.propertyDelete(entity, "nodeIdentity");
672
- ObjectHelper.propertyDelete(entity, "userIdentity");
673
- return entity;
914
+ return ObjectHelper.omit(entity, ["userIdentity"]);
915
+ }
916
+ /**
917
+ * Convert the entry to JSON-LD.
918
+ * @param entry The entry to convert.
919
+ * @param blob The optional blob to return.
920
+ * @returns The JSON-LD representation of the entry.
921
+ * @internal
922
+ */
923
+ entryToJsonLd(entry, blob) {
924
+ const jsonLd = {
925
+ "@context": JsonLdProcessor.combineContexts([
926
+ BlobStorageContexts.ContextRoot,
927
+ BlobStorageContexts.ContextRootCommon,
928
+ SchemaOrgContexts.ContextRoot
929
+ ], entry?.metadata?.["@context"]),
930
+ id: entry.id,
931
+ type: BlobStorageTypes.Entry,
932
+ dateCreated: entry.dateCreated,
933
+ dateModified: entry.dateModified,
934
+ blobSize: entry.blobSize,
935
+ blobHash: entry.blobHash,
936
+ encodingFormat: entry?.encodingFormat,
937
+ fileExtension: entry?.fileExtension,
938
+ metadata: entry?.metadata,
939
+ blob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined,
940
+ isEncrypted: entry.isEncrypted,
941
+ compression: entry.compression
942
+ };
943
+ return jsonLd;
674
944
  }
675
945
  }
676
946
 
677
947
  /**
678
- * Class representing metadata for the blob storage.
948
+ * Class representing entry for the blob storage.
679
949
  */
680
- let BlobMetadata = class BlobMetadata {
950
+ let BlobStorageEntry = class BlobStorageEntry {
681
951
  /**
682
952
  * The id for the blob.
683
953
  */
684
954
  id;
955
+ /**
956
+ * The date/time when the entry was created.
957
+ */
958
+ dateCreated;
959
+ /**
960
+ * The date/time when the entry was modified.
961
+ */
962
+ dateModified;
963
+ /**
964
+ * The length of the data in the blob.
965
+ */
966
+ blobSize;
967
+ /**
968
+ * The hash of the data in the blob.
969
+ */
970
+ blobHash;
685
971
  /**
686
972
  * The mime type for the blob.
687
973
  */
688
- mimeType;
974
+ encodingFormat;
689
975
  /**
690
976
  * The extension.
691
977
  */
692
- extension;
978
+ fileExtension;
693
979
  /**
694
980
  * The metadata for the blob as JSON-LD.
695
981
  */
696
982
  metadata;
697
983
  /**
698
- * The user identity that created the blob.
984
+ * Is the entry encrypted.
699
985
  */
700
- userIdentity;
986
+ isEncrypted;
701
987
  /**
702
- * The node identity that created the blob.
988
+ * Is the entry compressed.
989
+ */
990
+ compression;
991
+ /**
992
+ * The user identity that created the blob.
703
993
  */
704
- nodeIdentity;
994
+ userIdentity;
705
995
  };
706
996
  __decorate([
707
997
  property({ type: "string", isPrimary: true }),
708
998
  __metadata("design:type", String)
709
- ], BlobMetadata.prototype, "id", void 0);
999
+ ], BlobStorageEntry.prototype, "id", void 0);
710
1000
  __decorate([
711
- property({ type: "string" }),
1001
+ property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
1002
+ __metadata("design:type", String)
1003
+ ], BlobStorageEntry.prototype, "dateCreated", void 0);
1004
+ __decorate([
1005
+ property({
1006
+ type: "string",
1007
+ format: "date-time",
1008
+ sortDirection: SortDirection.Descending,
1009
+ optional: true
1010
+ }),
712
1011
  __metadata("design:type", String)
713
- ], BlobMetadata.prototype, "mimeType", void 0);
1012
+ ], BlobStorageEntry.prototype, "dateModified", void 0);
1013
+ __decorate([
1014
+ property({ type: "number" }),
1015
+ __metadata("design:type", Number)
1016
+ ], BlobStorageEntry.prototype, "blobSize", void 0);
714
1017
  __decorate([
715
1018
  property({ type: "string" }),
716
1019
  __metadata("design:type", String)
717
- ], BlobMetadata.prototype, "extension", void 0);
1020
+ ], BlobStorageEntry.prototype, "blobHash", void 0);
1021
+ __decorate([
1022
+ property({ type: "string", optional: true }),
1023
+ __metadata("design:type", String)
1024
+ ], BlobStorageEntry.prototype, "encodingFormat", void 0);
1025
+ __decorate([
1026
+ property({ type: "string", optional: true }),
1027
+ __metadata("design:type", String)
1028
+ ], BlobStorageEntry.prototype, "fileExtension", void 0);
718
1029
  __decorate([
719
- property({ type: "object", itemTypeRef: "IJsonLdNodeObject" }),
1030
+ property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
720
1031
  __metadata("design:type", Object)
721
- ], BlobMetadata.prototype, "metadata", void 0);
1032
+ ], BlobStorageEntry.prototype, "metadata", void 0);
722
1033
  __decorate([
723
- property({ type: "string" }),
1034
+ property({ type: "boolean" }),
1035
+ __metadata("design:type", Boolean)
1036
+ ], BlobStorageEntry.prototype, "isEncrypted", void 0);
1037
+ __decorate([
1038
+ property({ type: "string", optional: true }),
724
1039
  __metadata("design:type", String)
725
- ], BlobMetadata.prototype, "userIdentity", void 0);
1040
+ ], BlobStorageEntry.prototype, "compression", void 0);
726
1041
  __decorate([
727
- property({ type: "string" }),
1042
+ property({ type: "string", optional: true }),
728
1043
  __metadata("design:type", String)
729
- ], BlobMetadata.prototype, "nodeIdentity", void 0);
730
- BlobMetadata = __decorate([
1044
+ ], BlobStorageEntry.prototype, "userIdentity", void 0);
1045
+ BlobStorageEntry = __decorate([
731
1046
  entity()
732
- ], BlobMetadata);
1047
+ ], BlobStorageEntry);
733
1048
 
734
1049
  /**
735
1050
  * These are dummy entry points for the blob storage service.
@@ -751,7 +1066,7 @@ const restEntryPoints = [
751
1066
  * Initialize the schema for the blob storage entities.
752
1067
  */
753
1068
  function initSchema() {
754
- EntitySchemaFactory.register("BlobMetadata", () => EntitySchemaHelper.getSchema(BlobMetadata));
1069
+ EntitySchemaFactory.register("BlobStorageEntry", () => EntitySchemaHelper.getSchema(BlobStorageEntry));
755
1070
  }
756
1071
 
757
- export { BlobMetadata, BlobStorageService, blobStorageCreate, blobStorageGet, blobStorageGetContent, blobStorageRemove, blobStorageUpdate, generateRestRoutesBlobStorage, initSchema, restEntryPoints, tagsBlobStorage };
1072
+ export { BlobStorageEntry, BlobStorageService, blobStorageCreate, blobStorageGet, blobStorageGetContent, blobStorageList, blobStorageRemove, blobStorageUpdate, generateRestRoutesBlobStorage, initSchema, restEntryPoints, tagsBlobStorage };