@twin.org/blob-storage-service 0.0.1-next.34 → 0.0.1-next.36

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.
@@ -98,7 +98,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
98
98
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
99
99
  },
100
100
  query: {
101
- includeContent: true
101
+ includeContent: "true"
102
102
  }
103
103
  }
104
104
  }
@@ -188,7 +188,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
188
188
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
189
189
  },
190
190
  query: {
191
- download: true,
191
+ download: "true",
192
192
  filename: "my-file.pdf"
193
193
  }
194
194
  }
@@ -277,7 +277,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
277
277
  ]
278
278
  };
279
279
  const blobStorageListRoute = {
280
- operationId: `${camelTypeName}Get`,
280
+ operationId: `${camelTypeName}Query`,
281
281
  summary: `Query the items from ${lowerName}`,
282
282
  tag: options?.tagName ?? tagsBlobStorage[0].name,
283
283
  method: "GET",
@@ -400,7 +400,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
400
400
  core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
401
401
  core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
402
402
  const component = core.ComponentFactory.get(componentName);
403
- const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, request.body.namespace, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
403
+ const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, {
404
+ disableEncryption: request.body.disableEncryption,
405
+ overrideVaultKeyId: request.body.overrideVaultKeyId,
406
+ namespace: request.body.namespace
407
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
404
408
  return {
405
409
  statusCode: web.HttpStatusCode.created,
406
410
  headers: {
@@ -421,7 +425,11 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
421
425
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
422
426
  const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
423
427
  const component = core.ComponentFactory.get(componentName);
424
- const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
428
+ const result = await component.get(request.pathParams.id, {
429
+ includeContent: core.Coerce.boolean(request.query?.includeContent),
430
+ decompress: core.Coerce.boolean(request.query?.decompress),
431
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
432
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
425
433
  return {
426
434
  headers: {
427
435
  [web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
@@ -441,16 +449,31 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
441
449
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
442
450
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
443
451
  const component = core.ComponentFactory.get(componentName);
444
- const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
452
+ const decompress = core.Coerce.boolean(request.query?.decompress);
453
+ const result = await component.get(request.pathParams.id, {
454
+ includeContent: true,
455
+ decompress,
456
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
457
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
445
458
  const encodingFormat = result?.encodingFormat ?? web.MimeTypes.OctetStream;
459
+ let compressedEncodingFormat;
460
+ let compressedExtension = "";
461
+ // If the entry is compressed and we are not decompressing
462
+ // we need to override the encoding format to the compressed type
463
+ // and append an additional extension to the filename.
464
+ if (result.compression && !decompress) {
465
+ compressedEncodingFormat =
466
+ result.compression === blobStorageModels.BlobStorageCompressionType.Gzip ? web.MimeTypes.Gzip : web.MimeTypes.Zlib;
467
+ compressedExtension = `.${web.MimeTypeHelper.defaultExtension(compressedEncodingFormat)}`;
468
+ }
446
469
  let filename = request.query?.filename;
447
470
  if (!core.Is.stringValue(filename)) {
448
- filename = `file.${result.fileExtension ?? web.MimeTypeHelper.defaultExtension(encodingFormat)}`;
471
+ filename = `file.${result.fileExtension ?? web.MimeTypeHelper.defaultExtension(encodingFormat)}${compressedExtension}`;
449
472
  }
450
473
  return {
451
474
  body: core.Is.stringBase64(result.blob) ? core.Converter.base64ToBytes(result.blob) : new Uint8Array(),
452
475
  attachment: {
453
- mimeType: encodingFormat,
476
+ mimeType: compressedEncodingFormat ?? encodingFormat,
454
477
  filename,
455
478
  inline: !(request.query?.download ?? false)
456
479
  }
@@ -566,10 +589,10 @@ class BlobStorageService {
566
589
  }
567
590
  this._entryEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
568
591
  if (core.Is.stringValue(options?.vaultConnectorType)) {
569
- this._vaultConnector = vaultModels.VaultConnectorFactory.getIfExists(options.vaultConnectorType);
592
+ this._vaultConnector = vaultModels.VaultConnectorFactory.get(options.vaultConnectorType);
570
593
  }
571
594
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
572
- this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
595
+ this._vaultKeyId = options?.config?.vaultKeyId;
573
596
  this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
574
597
  this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
575
598
  standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
@@ -580,21 +603,28 @@ class BlobStorageService {
580
603
  * @param encodingFormat Mime type for the blob, will be detected if left undefined.
581
604
  * @param fileExtension Extension for the blob, will be detected if left undefined.
582
605
  * @param metadata Data for the custom metadata as JSON-LD.
583
- * @param namespace The namespace to use for storing, defaults to component configured namespace.
606
+ * @param options Optional options for the creation of the blob.
607
+ * @param options.disableEncryption Disables encryption if enabled by default.
608
+ * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
609
+ * @param options.compress Optional compression type to use for the blob, defaults to no compression.*
610
+ * @param options.namespace The namespace to use for storing, defaults to component configured namespace.
584
611
  * @param userIdentity The user identity to use with storage operations.
585
612
  * @param nodeIdentity The node identity to use with storage operations.
586
613
  * @returns The id of the stored blob in urn format.
587
614
  */
588
- async create(blob, encodingFormat, fileExtension, metadata, namespace, userIdentity, nodeIdentity) {
615
+ async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
589
616
  core.Guards.stringBase64(this.CLASS_NAME, "blob", blob);
590
617
  if (this._includeUserIdentity) {
591
618
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
592
619
  }
593
- if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
620
+ const disableEncryption = options?.disableEncryption ?? false;
621
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
622
+ const encryptionEnabled = !disableEncryption && core.Is.stringValue(vaultKeyId);
623
+ if (this._includeNodeIdentity || encryptionEnabled) {
594
624
  core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
595
625
  }
596
626
  try {
597
- const connectorNamespace = namespace ?? this._defaultNamespace;
627
+ const connectorNamespace = options?.namespace ?? this._defaultNamespace;
598
628
  const blobStorageConnector = blobStorageModels.BlobStorageConnectorFactory.get(connectorNamespace);
599
629
  // Convert the base64 data into bytes
600
630
  let storeBlob = core.Converter.base64ToBytes(blob);
@@ -614,9 +644,15 @@ class BlobStorageService {
614
644
  core.Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
615
645
  }
616
646
  const blobHash = `sha256:${core.Converter.bytesToBase64(crypto.Sha256.sum256(storeBlob))}`;
647
+ if (!core.Is.empty(options?.compress)) {
648
+ storeBlob = await core.Compression.compress(storeBlob, options.compress);
649
+ }
617
650
  // If we have a vault connector then encrypt the data.
618
- if (this._vaultConnector) {
619
- storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
651
+ if (encryptionEnabled) {
652
+ if (core.Is.empty(this._vaultConnector)) {
653
+ throw new core.GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
654
+ }
655
+ storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
620
656
  }
621
657
  // Set the blob in the storage connector, which may now be encrypted
622
658
  const blobId = await blobStorageConnector.set(storeBlob);
@@ -628,7 +664,9 @@ class BlobStorageService {
628
664
  blobHash,
629
665
  encodingFormat,
630
666
  fileExtension,
631
- metadata
667
+ metadata,
668
+ isEncrypted: encryptionEnabled,
669
+ compression: options?.compress
632
670
  };
633
671
  const conditions = [];
634
672
  if (this._includeUserIdentity) {
@@ -649,14 +687,19 @@ class BlobStorageService {
649
687
  /**
650
688
  * Get the blob entry.
651
689
  * @param id The id of the blob to get in urn format.
652
- * @param includeContent Include the content, or just get the metadata.
690
+ * @param options Optional options for the retrieval of the blob.
691
+ * @param options.includeContent Include the content, or just get the metadata.
692
+ * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
693
+ * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
653
694
  * @param userIdentity The user identity to use with storage operations.
654
695
  * @param nodeIdentity The node identity to use with storage operations.
655
696
  * @returns The entry and data for the blob if it can be found.
656
697
  * @throws Not found error if the blob cannot be found.
657
698
  */
658
- async get(id, includeContent, userIdentity, nodeIdentity) {
699
+ async get(id, options, userIdentity, nodeIdentity) {
659
700
  core.Urn.guard(this.CLASS_NAME, "id", id);
701
+ const includeContent = options?.includeContent ?? false;
702
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
660
703
  const conditions = [];
661
704
  if (this._includeUserIdentity) {
662
705
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
@@ -683,9 +726,16 @@ class BlobStorageService {
683
726
  if (core.Is.undefined(returnBlob)) {
684
727
  throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
685
728
  }
686
- // If we have a vault connector then decrypt the data.
687
- if (this._vaultConnector) {
688
- returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
729
+ // If the data is encrypted then decrypt it.
730
+ const decryptionEnabled = blobEntry.isEncrypted && core.Is.stringValue(vaultKeyId);
731
+ if (decryptionEnabled) {
732
+ if (core.Is.empty(this._vaultConnector)) {
733
+ throw new core.GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
734
+ }
735
+ returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
736
+ }
737
+ if (!core.Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {
738
+ returnBlob = await core.Compression.decompress(returnBlob, blobEntry.compression);
689
739
  }
690
740
  }
691
741
  const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
@@ -733,7 +783,9 @@ class BlobStorageService {
733
783
  blobHash: blobEntry.blobHash,
734
784
  encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
735
785
  fileExtension: fileExtension ?? blobEntry.fileExtension,
736
- metadata: metadata ?? blobEntry.metadata
786
+ metadata: metadata ?? blobEntry.metadata,
787
+ isEncrypted: blobEntry.isEncrypted,
788
+ compression: blobEntry.compression
737
789
  };
738
790
  const conditions = [];
739
791
  if (this._includeUserIdentity) {
@@ -828,10 +880,6 @@ class BlobStorageService {
828
880
  sortDirection: orderDirection
829
881
  }
830
882
  ], undefined, cursor, pageSize);
831
- for (const entity of result.entities) {
832
- core.ObjectHelper.propertyDelete(entity, "nodeIdentity");
833
- core.ObjectHelper.propertyDelete(entity, "userIdentity");
834
- }
835
883
  let context = [
836
884
  standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
837
885
  blobStorageModels.BlobStorageContexts.ContextRoot,
@@ -915,9 +963,7 @@ class BlobStorageService {
915
963
  if (core.Is.empty(entity$1)) {
916
964
  throw new core.NotFoundError(this.CLASS_NAME, "entityNotFound", id);
917
965
  }
918
- core.ObjectHelper.propertyDelete(entity$1, "nodeIdentity");
919
- core.ObjectHelper.propertyDelete(entity$1, "userIdentity");
920
- return entity$1;
966
+ return core.ObjectHelper.omit(entity$1, ["nodeIdentity", "userIdentity"]);
921
967
  }
922
968
  /**
923
969
  * Convert the entry to JSON-LD.
@@ -942,7 +988,9 @@ class BlobStorageService {
942
988
  encodingFormat: entry?.encodingFormat,
943
989
  fileExtension: entry?.fileExtension,
944
990
  metadata: entry?.metadata,
945
- blob: core.Is.uint8Array(blob) ? core.Converter.bytesToBase64(blob) : undefined
991
+ blob: core.Is.uint8Array(blob) ? core.Converter.bytesToBase64(blob) : undefined,
992
+ isEncrypted: entry.isEncrypted,
993
+ compression: entry.compression
946
994
  };
947
995
  return jsonLd;
948
996
  }
@@ -984,6 +1032,14 @@ exports.BlobStorageEntry = class BlobStorageEntry {
984
1032
  * The metadata for the blob as JSON-LD.
985
1033
  */
986
1034
  metadata;
1035
+ /**
1036
+ * Is the entry encrypted.
1037
+ */
1038
+ isEncrypted;
1039
+ /**
1040
+ * Is the entry compressed.
1041
+ */
1042
+ compression;
987
1043
  /**
988
1044
  * The user identity that created the blob.
989
1045
  */
@@ -1030,6 +1086,14 @@ __decorate([
1030
1086
  entity.property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
1031
1087
  __metadata("design:type", Object)
1032
1088
  ], exports.BlobStorageEntry.prototype, "metadata", void 0);
1089
+ __decorate([
1090
+ entity.property({ type: "boolean" }),
1091
+ __metadata("design:type", Boolean)
1092
+ ], exports.BlobStorageEntry.prototype, "isEncrypted", void 0);
1093
+ __decorate([
1094
+ entity.property({ type: "string", optional: true }),
1095
+ __metadata("design:type", String)
1096
+ ], exports.BlobStorageEntry.prototype, "compression", void 0);
1033
1097
  __decorate([
1034
1098
  entity.property({ type: "string", optional: true }),
1035
1099
  __metadata("design:type", String)
@@ -1,6 +1,6 @@
1
1
  import { HttpParameterHelper } from '@twin.org/api-models';
2
- import { BlobStorageTypes, BlobStorageContexts, BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
3
- import { StringHelper, Guards, ComponentFactory, Is, Converter, Coerce, GeneralError, Validation, ObjectHelper, Urn, NotFoundError } from '@twin.org/core';
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
4
  import { SchemaOrgContexts, SchemaOrgTypes, SchemaOrgDataTypes } from '@twin.org/standards-schema-org';
5
5
  import { HttpStatusCode, HeaderTypes, MimeTypes, MimeTypeHelper } from '@twin.org/web';
6
6
  import { Sha256 } from '@twin.org/crypto';
@@ -96,7 +96,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
96
96
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
97
97
  },
98
98
  query: {
99
- includeContent: true
99
+ includeContent: "true"
100
100
  }
101
101
  }
102
102
  }
@@ -186,7 +186,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
186
186
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
187
187
  },
188
188
  query: {
189
- download: true,
189
+ download: "true",
190
190
  filename: "my-file.pdf"
191
191
  }
192
192
  }
@@ -275,7 +275,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
275
275
  ]
276
276
  };
277
277
  const blobStorageListRoute = {
278
- operationId: `${camelTypeName}Get`,
278
+ operationId: `${camelTypeName}Query`,
279
279
  summary: `Query the items from ${lowerName}`,
280
280
  tag: options?.tagName ?? tagsBlobStorage[0].name,
281
281
  method: "GET",
@@ -398,7 +398,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
398
398
  Guards.object(ROUTES_SOURCE, "request.body", request.body);
399
399
  Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
400
400
  const component = ComponentFactory.get(componentName);
401
- const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, request.body.namespace, httpRequestContext.userIdentity, 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);
402
406
  return {
403
407
  statusCode: HttpStatusCode.created,
404
408
  headers: {
@@ -419,7 +423,11 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
419
423
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
420
424
  const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
421
425
  const component = ComponentFactory.get(componentName);
422
- 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);
423
431
  return {
424
432
  headers: {
425
433
  [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
@@ -439,16 +447,31 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
439
447
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
440
448
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
441
449
  const component = ComponentFactory.get(componentName);
442
- const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
450
+ const decompress = Coerce.boolean(request.query?.decompress);
451
+ const result = await component.get(request.pathParams.id, {
452
+ includeContent: true,
453
+ decompress,
454
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
455
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
443
456
  const encodingFormat = result?.encodingFormat ?? MimeTypes.OctetStream;
457
+ let compressedEncodingFormat;
458
+ let compressedExtension = "";
459
+ // If the entry is compressed and we are not decompressing
460
+ // we need to override the encoding format to the compressed type
461
+ // and append an additional extension to the filename.
462
+ if (result.compression && !decompress) {
463
+ compressedEncodingFormat =
464
+ result.compression === BlobStorageCompressionType.Gzip ? MimeTypes.Gzip : MimeTypes.Zlib;
465
+ compressedExtension = `.${MimeTypeHelper.defaultExtension(compressedEncodingFormat)}`;
466
+ }
444
467
  let filename = request.query?.filename;
445
468
  if (!Is.stringValue(filename)) {
446
- filename = `file.${result.fileExtension ?? MimeTypeHelper.defaultExtension(encodingFormat)}`;
469
+ filename = `file.${result.fileExtension ?? MimeTypeHelper.defaultExtension(encodingFormat)}${compressedExtension}`;
447
470
  }
448
471
  return {
449
472
  body: Is.stringBase64(result.blob) ? Converter.base64ToBytes(result.blob) : new Uint8Array(),
450
473
  attachment: {
451
- mimeType: encodingFormat,
474
+ mimeType: compressedEncodingFormat ?? encodingFormat,
452
475
  filename,
453
476
  inline: !(request.query?.download ?? false)
454
477
  }
@@ -564,10 +587,10 @@ class BlobStorageService {
564
587
  }
565
588
  this._entryEntityStorage = EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
566
589
  if (Is.stringValue(options?.vaultConnectorType)) {
567
- this._vaultConnector = VaultConnectorFactory.getIfExists(options.vaultConnectorType);
590
+ this._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType);
568
591
  }
569
592
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
570
- this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
593
+ this._vaultKeyId = options?.config?.vaultKeyId;
571
594
  this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
572
595
  this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
573
596
  SchemaOrgDataTypes.registerRedirects();
@@ -578,21 +601,28 @@ class BlobStorageService {
578
601
  * @param encodingFormat Mime type for the blob, will be detected if left undefined.
579
602
  * @param fileExtension Extension for the blob, will be detected if left undefined.
580
603
  * @param metadata Data for the custom metadata as JSON-LD.
581
- * @param namespace The namespace to use for storing, defaults to component configured namespace.
604
+ * @param options Optional options for the creation of the blob.
605
+ * @param options.disableEncryption Disables encryption if enabled by default.
606
+ * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
607
+ * @param options.compress Optional compression type to use for the blob, defaults to no compression.*
608
+ * @param options.namespace The namespace to use for storing, defaults to component configured namespace.
582
609
  * @param userIdentity The user identity to use with storage operations.
583
610
  * @param nodeIdentity The node identity to use with storage operations.
584
611
  * @returns The id of the stored blob in urn format.
585
612
  */
586
- async create(blob, encodingFormat, fileExtension, metadata, namespace, userIdentity, nodeIdentity) {
613
+ async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
587
614
  Guards.stringBase64(this.CLASS_NAME, "blob", blob);
588
615
  if (this._includeUserIdentity) {
589
616
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
590
617
  }
591
- if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
618
+ const disableEncryption = options?.disableEncryption ?? false;
619
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
620
+ const encryptionEnabled = !disableEncryption && Is.stringValue(vaultKeyId);
621
+ if (this._includeNodeIdentity || encryptionEnabled) {
592
622
  Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
593
623
  }
594
624
  try {
595
- const connectorNamespace = namespace ?? this._defaultNamespace;
625
+ const connectorNamespace = options?.namespace ?? this._defaultNamespace;
596
626
  const blobStorageConnector = BlobStorageConnectorFactory.get(connectorNamespace);
597
627
  // Convert the base64 data into bytes
598
628
  let storeBlob = Converter.base64ToBytes(blob);
@@ -612,9 +642,15 @@ class BlobStorageService {
612
642
  Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
613
643
  }
614
644
  const blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;
645
+ if (!Is.empty(options?.compress)) {
646
+ storeBlob = await Compression.compress(storeBlob, options.compress);
647
+ }
615
648
  // If we have a vault connector then encrypt the data.
616
- if (this._vaultConnector) {
617
- storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
649
+ if (encryptionEnabled) {
650
+ if (Is.empty(this._vaultConnector)) {
651
+ throw new GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
652
+ }
653
+ storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
618
654
  }
619
655
  // Set the blob in the storage connector, which may now be encrypted
620
656
  const blobId = await blobStorageConnector.set(storeBlob);
@@ -626,7 +662,9 @@ class BlobStorageService {
626
662
  blobHash,
627
663
  encodingFormat,
628
664
  fileExtension,
629
- metadata
665
+ metadata,
666
+ isEncrypted: encryptionEnabled,
667
+ compression: options?.compress
630
668
  };
631
669
  const conditions = [];
632
670
  if (this._includeUserIdentity) {
@@ -647,14 +685,19 @@ class BlobStorageService {
647
685
  /**
648
686
  * Get the blob entry.
649
687
  * @param id The id of the blob to get in urn format.
650
- * @param includeContent Include the content, or just get the metadata.
688
+ * @param options Optional options for the retrieval of the blob.
689
+ * @param options.includeContent Include the content, or just get the metadata.
690
+ * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
691
+ * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
651
692
  * @param userIdentity The user identity to use with storage operations.
652
693
  * @param nodeIdentity The node identity to use with storage operations.
653
694
  * @returns The entry and data for the blob if it can be found.
654
695
  * @throws Not found error if the blob cannot be found.
655
696
  */
656
- async get(id, includeContent, userIdentity, nodeIdentity) {
697
+ async get(id, options, userIdentity, nodeIdentity) {
657
698
  Urn.guard(this.CLASS_NAME, "id", id);
699
+ const includeContent = options?.includeContent ?? false;
700
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
658
701
  const conditions = [];
659
702
  if (this._includeUserIdentity) {
660
703
  Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
@@ -681,9 +724,16 @@ class BlobStorageService {
681
724
  if (Is.undefined(returnBlob)) {
682
725
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
683
726
  }
684
- // If we have a vault connector then decrypt the data.
685
- if (this._vaultConnector) {
686
- returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
727
+ // If the data is encrypted then decrypt it.
728
+ const decryptionEnabled = blobEntry.isEncrypted && Is.stringValue(vaultKeyId);
729
+ if (decryptionEnabled) {
730
+ if (Is.empty(this._vaultConnector)) {
731
+ throw new GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
732
+ }
733
+ returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
734
+ }
735
+ if (!Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {
736
+ returnBlob = await Compression.decompress(returnBlob, blobEntry.compression);
687
737
  }
688
738
  }
689
739
  const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
@@ -731,7 +781,9 @@ class BlobStorageService {
731
781
  blobHash: blobEntry.blobHash,
732
782
  encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
733
783
  fileExtension: fileExtension ?? blobEntry.fileExtension,
734
- metadata: metadata ?? blobEntry.metadata
784
+ metadata: metadata ?? blobEntry.metadata,
785
+ isEncrypted: blobEntry.isEncrypted,
786
+ compression: blobEntry.compression
735
787
  };
736
788
  const conditions = [];
737
789
  if (this._includeUserIdentity) {
@@ -826,10 +878,6 @@ class BlobStorageService {
826
878
  sortDirection: orderDirection
827
879
  }
828
880
  ], undefined, cursor, pageSize);
829
- for (const entity of result.entities) {
830
- ObjectHelper.propertyDelete(entity, "nodeIdentity");
831
- ObjectHelper.propertyDelete(entity, "userIdentity");
832
- }
833
881
  let context = [
834
882
  SchemaOrgContexts.ContextRoot,
835
883
  BlobStorageContexts.ContextRoot,
@@ -913,9 +961,7 @@ class BlobStorageService {
913
961
  if (Is.empty(entity)) {
914
962
  throw new NotFoundError(this.CLASS_NAME, "entityNotFound", id);
915
963
  }
916
- ObjectHelper.propertyDelete(entity, "nodeIdentity");
917
- ObjectHelper.propertyDelete(entity, "userIdentity");
918
- return entity;
964
+ return ObjectHelper.omit(entity, ["nodeIdentity", "userIdentity"]);
919
965
  }
920
966
  /**
921
967
  * Convert the entry to JSON-LD.
@@ -940,7 +986,9 @@ class BlobStorageService {
940
986
  encodingFormat: entry?.encodingFormat,
941
987
  fileExtension: entry?.fileExtension,
942
988
  metadata: entry?.metadata,
943
- blob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined
989
+ blob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined,
990
+ isEncrypted: entry.isEncrypted,
991
+ compression: entry.compression
944
992
  };
945
993
  return jsonLd;
946
994
  }
@@ -982,6 +1030,14 @@ let BlobStorageEntry = class BlobStorageEntry {
982
1030
  * The metadata for the blob as JSON-LD.
983
1031
  */
984
1032
  metadata;
1033
+ /**
1034
+ * Is the entry encrypted.
1035
+ */
1036
+ isEncrypted;
1037
+ /**
1038
+ * Is the entry compressed.
1039
+ */
1040
+ compression;
985
1041
  /**
986
1042
  * The user identity that created the blob.
987
1043
  */
@@ -1028,6 +1084,14 @@ __decorate([
1028
1084
  property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
1029
1085
  __metadata("design:type", Object)
1030
1086
  ], BlobStorageEntry.prototype, "metadata", void 0);
1087
+ __decorate([
1088
+ property({ type: "boolean" }),
1089
+ __metadata("design:type", Boolean)
1090
+ ], BlobStorageEntry.prototype, "isEncrypted", void 0);
1091
+ __decorate([
1092
+ property({ type: "string", optional: true }),
1093
+ __metadata("design:type", String)
1094
+ ], BlobStorageEntry.prototype, "compression", void 0);
1031
1095
  __decorate([
1032
1096
  property({ type: "string", optional: true }),
1033
1097
  __metadata("design:type", String)
@@ -1,4 +1,4 @@
1
- import { type IBlobStorageComponent, type IBlobStorageEntry, type IBlobStorageEntryList } from "@twin.org/blob-storage-models";
1
+ import { type BlobStorageCompressionType, type IBlobStorageComponent, type IBlobStorageEntry, type IBlobStorageEntryList } from "@twin.org/blob-storage-models";
2
2
  import { type IJsonLdNodeObject } from "@twin.org/data-json-ld";
3
3
  import { SortDirection, type EntityCondition } from "@twin.org/entity";
4
4
  import type { IBlobStorageServiceConstructorOptions } from "./models/IBlobStorageServiceConstructorOptions";
@@ -25,22 +25,38 @@ export declare class BlobStorageService implements IBlobStorageComponent {
25
25
  * @param encodingFormat Mime type for the blob, will be detected if left undefined.
26
26
  * @param fileExtension Extension for the blob, will be detected if left undefined.
27
27
  * @param metadata Data for the custom metadata as JSON-LD.
28
- * @param namespace The namespace to use for storing, defaults to component configured namespace.
28
+ * @param options Optional options for the creation of the blob.
29
+ * @param options.disableEncryption Disables encryption if enabled by default.
30
+ * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
31
+ * @param options.compress Optional compression type to use for the blob, defaults to no compression.*
32
+ * @param options.namespace The namespace to use for storing, defaults to component configured namespace.
29
33
  * @param userIdentity The user identity to use with storage operations.
30
34
  * @param nodeIdentity The node identity to use with storage operations.
31
35
  * @returns The id of the stored blob in urn format.
32
36
  */
33
- create(blob: string, encodingFormat?: string, fileExtension?: string, metadata?: IJsonLdNodeObject, namespace?: string, userIdentity?: string, nodeIdentity?: string): Promise<string>;
37
+ create(blob: string, encodingFormat?: string, fileExtension?: string, metadata?: IJsonLdNodeObject, options?: {
38
+ disableEncryption?: boolean;
39
+ overrideVaultKeyId?: string;
40
+ compress?: BlobStorageCompressionType;
41
+ namespace?: string;
42
+ }, userIdentity?: string, nodeIdentity?: string): Promise<string>;
34
43
  /**
35
44
  * Get the blob entry.
36
45
  * @param id The id of the blob to get in urn format.
37
- * @param includeContent Include the content, or just get the metadata.
46
+ * @param options Optional options for the retrieval of the blob.
47
+ * @param options.includeContent Include the content, or just get the metadata.
48
+ * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
49
+ * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
38
50
  * @param userIdentity The user identity to use with storage operations.
39
51
  * @param nodeIdentity The node identity to use with storage operations.
40
52
  * @returns The entry and data for the blob if it can be found.
41
53
  * @throws Not found error if the blob cannot be found.
42
54
  */
43
- get(id: string, includeContent: boolean, userIdentity?: string, nodeIdentity?: string): Promise<IBlobStorageEntry>;
55
+ get(id: string, options?: {
56
+ includeContent?: boolean;
57
+ decompress?: boolean;
58
+ overrideVaultKeyId?: string;
59
+ }, userIdentity?: string, nodeIdentity?: string): Promise<IBlobStorageEntry>;
44
60
  /**
45
61
  * Update the blob with metadata.
46
62
  * @param id The id of the blob entry to update.
@@ -1,3 +1,4 @@
1
+ import type { BlobStorageCompressionType } from "@twin.org/blob-storage-models";
1
2
  import type { IJsonLdNodeObject } from "@twin.org/data-json-ld";
2
3
  /**
3
4
  * Class representing entry for the blob storage.
@@ -35,6 +36,14 @@ export declare class BlobStorageEntry {
35
36
  * The metadata for the blob as JSON-LD.
36
37
  */
37
38
  metadata?: IJsonLdNodeObject;
39
+ /**
40
+ * Is the entry encrypted.
41
+ */
42
+ isEncrypted: boolean;
43
+ /**
44
+ * Is the entry compressed.
45
+ */
46
+ compression?: BlobStorageCompressionType;
38
47
  /**
39
48
  * The user identity that created the blob.
40
49
  */
@@ -3,8 +3,7 @@
3
3
  */
4
4
  export interface IBlobStorageServiceConfig {
5
5
  /**
6
- * The name of the vault key to use for encryption if the service has a vault connector configured.
7
- * @default blob-storage.
6
+ * The name of the vault key to use for encryption, if not configured no encryption will happen.
8
7
  */
9
8
  vaultKeyId?: string;
10
9
  /**
@@ -9,7 +9,7 @@ export interface IBlobStorageServiceConstructorOptions {
9
9
  */
10
10
  entryEntityStorageType?: string;
11
11
  /**
12
- * The type of the vault connector for encryption, if undefined no encryption will be performed.
12
+ * The type of the vault connector for encryption.
13
13
  */
14
14
  vaultConnectorType?: string;
15
15
  /**