@twin.org/blob-storage-service 0.0.2-next.4 → 0.0.2-next.5
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/cjs/index.cjs +34 -34
- package/dist/esm/index.mjs +34 -34
- package/dist/types/blobStorageService.d.ts +3 -3
- package/docs/changelog.md +16 -0
- package/docs/open-api/spec.json +25 -28
- package/docs/reference/classes/BlobStorageService.md +3 -7
- package/locales/en.json +3 -1
- package/package.json +7 -3
package/dist/cjs/index.cjs
CHANGED
|
@@ -525,7 +525,7 @@ async function blobStorageList(httpRequestContext, componentName, request) {
|
|
|
525
525
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
526
526
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
527
527
|
const component = core.ComponentFactory.get(componentName);
|
|
528
|
-
const result = await component.query(apiModels.HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, core.Coerce.number(request.query?.
|
|
528
|
+
const result = await component.query(apiModels.HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, core.Coerce.number(request.query?.limit), httpRequestContext.userIdentity);
|
|
529
529
|
return {
|
|
530
530
|
headers: {
|
|
531
531
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -540,15 +540,15 @@ async function blobStorageList(httpRequestContext, componentName, request) {
|
|
|
540
540
|
* Service for performing blob storage operations to a connector.
|
|
541
541
|
*/
|
|
542
542
|
class BlobStorageService {
|
|
543
|
+
/**
|
|
544
|
+
* Runtime name for the class.
|
|
545
|
+
*/
|
|
546
|
+
static CLASS_NAME = "BlobStorageService";
|
|
543
547
|
/**
|
|
544
548
|
* The namespace supported by the blob storage service.
|
|
545
549
|
* @internal
|
|
546
550
|
*/
|
|
547
551
|
static _NAMESPACE = "blob";
|
|
548
|
-
/**
|
|
549
|
-
* Runtime name for the class.
|
|
550
|
-
*/
|
|
551
|
-
CLASS_NAME = "BlobStorageService";
|
|
552
552
|
/**
|
|
553
553
|
* The namespace of the default storage connector to use.
|
|
554
554
|
* Defaults to the first entry in the factory if not provided.
|
|
@@ -582,7 +582,7 @@ class BlobStorageService {
|
|
|
582
582
|
constructor(options) {
|
|
583
583
|
const names = blobStorageModels.BlobStorageConnectorFactory.names();
|
|
584
584
|
if (names.length === 0) {
|
|
585
|
-
throw new core.GeneralError(
|
|
585
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "noConnectors");
|
|
586
586
|
}
|
|
587
587
|
this._entryEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
|
|
588
588
|
if (core.Is.stringValue(options?.vaultConnectorType)) {
|
|
@@ -609,9 +609,9 @@ class BlobStorageService {
|
|
|
609
609
|
* @returns The id of the stored blob in urn format.
|
|
610
610
|
*/
|
|
611
611
|
async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
|
|
612
|
-
core.Guards.stringBase64(
|
|
612
|
+
core.Guards.stringBase64(BlobStorageService.CLASS_NAME, "blob", blob);
|
|
613
613
|
if (this._partitionPerUser) {
|
|
614
|
-
core.Guards.stringValue(
|
|
614
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
615
615
|
}
|
|
616
616
|
const disableEncryption = options?.disableEncryption ?? false;
|
|
617
617
|
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
@@ -634,7 +634,7 @@ class BlobStorageService {
|
|
|
634
634
|
if (core.Is.object(metadata)) {
|
|
635
635
|
const validationFailures = [];
|
|
636
636
|
dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
|
|
637
|
-
core.Validation.asValidationError(
|
|
637
|
+
core.Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
638
638
|
}
|
|
639
639
|
const blobHash = `sha256:${core.Converter.bytesToBase64(crypto.Sha256.sum256(storeBlob))}`;
|
|
640
640
|
if (!core.Is.empty(options?.compress)) {
|
|
@@ -642,9 +642,9 @@ class BlobStorageService {
|
|
|
642
642
|
}
|
|
643
643
|
// If we have a vault connector then encrypt the data.
|
|
644
644
|
if (encryptionEnabled) {
|
|
645
|
-
core.Guards.stringValue(
|
|
645
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
646
646
|
if (core.Is.empty(this._vaultConnector)) {
|
|
647
|
-
throw new core.GeneralError(
|
|
647
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
648
648
|
}
|
|
649
649
|
storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
|
|
650
650
|
}
|
|
@@ -671,7 +671,7 @@ class BlobStorageService {
|
|
|
671
671
|
return blobId;
|
|
672
672
|
}
|
|
673
673
|
catch (error) {
|
|
674
|
-
throw new core.GeneralError(
|
|
674
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "createFailed", undefined, error);
|
|
675
675
|
}
|
|
676
676
|
}
|
|
677
677
|
/**
|
|
@@ -687,12 +687,12 @@ class BlobStorageService {
|
|
|
687
687
|
* @throws Not found error if the blob cannot be found.
|
|
688
688
|
*/
|
|
689
689
|
async get(id, options, userIdentity, nodeIdentity) {
|
|
690
|
-
core.Urn.guard(
|
|
690
|
+
core.Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
691
691
|
const includeContent = options?.includeContent ?? false;
|
|
692
692
|
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
693
693
|
const conditions = [];
|
|
694
694
|
if (this._partitionPerUser) {
|
|
695
|
-
core.Guards.stringValue(
|
|
695
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
696
696
|
conditions.push({
|
|
697
697
|
property: "userIdentity",
|
|
698
698
|
comparison: entity.ComparisonOperator.Equals,
|
|
@@ -706,14 +706,14 @@ class BlobStorageService {
|
|
|
706
706
|
const blobStorageConnector = this.getConnector(id);
|
|
707
707
|
returnBlob = await blobStorageConnector.get(id);
|
|
708
708
|
if (core.Is.undefined(returnBlob)) {
|
|
709
|
-
throw new core.NotFoundError(
|
|
709
|
+
throw new core.NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
710
710
|
}
|
|
711
711
|
// If the data is encrypted then decrypt it.
|
|
712
712
|
const decryptionEnabled = blobEntry.isEncrypted && core.Is.stringValue(vaultKeyId);
|
|
713
713
|
if (decryptionEnabled) {
|
|
714
|
-
core.Guards.stringValue(
|
|
714
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
715
715
|
if (core.Is.empty(this._vaultConnector)) {
|
|
716
|
-
throw new core.GeneralError(
|
|
716
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
717
717
|
}
|
|
718
718
|
returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
|
|
719
719
|
}
|
|
@@ -725,7 +725,7 @@ class BlobStorageService {
|
|
|
725
725
|
return dataJsonLd.JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
726
726
|
}
|
|
727
727
|
catch (error) {
|
|
728
|
-
throw new core.GeneralError(
|
|
728
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "getFailed", undefined, error);
|
|
729
729
|
}
|
|
730
730
|
}
|
|
731
731
|
/**
|
|
@@ -739,19 +739,19 @@ class BlobStorageService {
|
|
|
739
739
|
* @throws Not found error if the blob cannot be found.
|
|
740
740
|
*/
|
|
741
741
|
async update(id, encodingFormat, fileExtension, metadata, userIdentity) {
|
|
742
|
-
core.Urn.guard(
|
|
742
|
+
core.Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
743
743
|
if (this._partitionPerUser) {
|
|
744
|
-
core.Guards.stringValue(
|
|
744
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
745
745
|
}
|
|
746
746
|
try {
|
|
747
747
|
const blobEntry = await this._entryEntityStorage.get(id);
|
|
748
748
|
if (core.Is.undefined(blobEntry)) {
|
|
749
|
-
throw new core.NotFoundError(
|
|
749
|
+
throw new core.NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
750
750
|
}
|
|
751
751
|
if (core.Is.object(metadata)) {
|
|
752
752
|
const validationFailures = [];
|
|
753
753
|
await dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
|
|
754
|
-
core.Validation.asValidationError(
|
|
754
|
+
core.Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
755
755
|
}
|
|
756
756
|
// Now store the entry in entity storage
|
|
757
757
|
const updatedBlobEntry = {
|
|
@@ -774,7 +774,7 @@ class BlobStorageService {
|
|
|
774
774
|
await this._entryEntityStorage.set(updatedBlobEntry, conditions);
|
|
775
775
|
}
|
|
776
776
|
catch (error) {
|
|
777
|
-
throw new core.GeneralError(
|
|
777
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "updateFailed", undefined, error);
|
|
778
778
|
}
|
|
779
779
|
}
|
|
780
780
|
/**
|
|
@@ -784,9 +784,9 @@ class BlobStorageService {
|
|
|
784
784
|
* @returns Nothing.
|
|
785
785
|
*/
|
|
786
786
|
async remove(id, userIdentity) {
|
|
787
|
-
core.Urn.guard(
|
|
787
|
+
core.Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
788
788
|
if (this._partitionPerUser) {
|
|
789
|
-
core.Guards.stringValue(
|
|
789
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
790
790
|
}
|
|
791
791
|
try {
|
|
792
792
|
const blobStorageConnector = this.getConnector(id);
|
|
@@ -797,11 +797,11 @@ class BlobStorageService {
|
|
|
797
797
|
await this._entryEntityStorage.remove(id, conditions);
|
|
798
798
|
const removed = await blobStorageConnector.remove(id);
|
|
799
799
|
if (!removed) {
|
|
800
|
-
throw new core.NotFoundError(
|
|
800
|
+
throw new core.NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
801
801
|
}
|
|
802
802
|
}
|
|
803
803
|
catch (error) {
|
|
804
|
-
throw new core.GeneralError(
|
|
804
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "removeFailed", undefined, error);
|
|
805
805
|
}
|
|
806
806
|
}
|
|
807
807
|
/**
|
|
@@ -810,18 +810,18 @@ class BlobStorageService {
|
|
|
810
810
|
* @param orderBy The order for the results, defaults to created.
|
|
811
811
|
* @param orderByDirection The direction for the order, defaults to descending.
|
|
812
812
|
* @param cursor The cursor to request the next page of entries.
|
|
813
|
-
* @param
|
|
813
|
+
* @param limit The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
|
|
814
814
|
* @param userIdentity The user identity to use with storage operations.
|
|
815
815
|
* @returns All the entries for the storage matching the conditions,
|
|
816
816
|
* and a cursor which can be used to request more entities.
|
|
817
817
|
*/
|
|
818
|
-
async query(conditions, orderBy, orderByDirection, cursor,
|
|
818
|
+
async query(conditions, orderBy, orderByDirection, cursor, limit, userIdentity) {
|
|
819
819
|
const finalConditions = {
|
|
820
820
|
conditions: [],
|
|
821
821
|
logicalOperator: entity.LogicalOperator.And
|
|
822
822
|
};
|
|
823
823
|
if (this._partitionPerUser) {
|
|
824
|
-
core.Guards.stringValue(
|
|
824
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
825
825
|
finalConditions.conditions.push({
|
|
826
826
|
property: "userIdentity",
|
|
827
827
|
comparison: entity.ComparisonOperator.Equals,
|
|
@@ -838,7 +838,7 @@ class BlobStorageService {
|
|
|
838
838
|
property: orderProperty,
|
|
839
839
|
sortDirection: orderDirection
|
|
840
840
|
}
|
|
841
|
-
], undefined, cursor,
|
|
841
|
+
], undefined, cursor, limit);
|
|
842
842
|
let context = [
|
|
843
843
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
|
|
844
844
|
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
@@ -867,7 +867,7 @@ class BlobStorageService {
|
|
|
867
867
|
getConnector(id) {
|
|
868
868
|
const idUri = core.Urn.fromValidString(id);
|
|
869
869
|
if (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {
|
|
870
|
-
throw new core.GeneralError(
|
|
870
|
+
throw new core.GeneralError(BlobStorageService.CLASS_NAME, "namespaceMismatch", {
|
|
871
871
|
namespace: BlobStorageService._NAMESPACE,
|
|
872
872
|
id
|
|
873
873
|
});
|
|
@@ -885,7 +885,7 @@ class BlobStorageService {
|
|
|
885
885
|
async internalGet(id, userIdentity) {
|
|
886
886
|
const conditions = [];
|
|
887
887
|
if (this._partitionPerUser) {
|
|
888
|
-
core.Guards.stringValue(
|
|
888
|
+
core.Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
889
889
|
conditions.push({
|
|
890
890
|
property: "userIdentity",
|
|
891
891
|
comparison: entity.ComparisonOperator.Equals,
|
|
@@ -911,7 +911,7 @@ class BlobStorageService {
|
|
|
911
911
|
entity$1 = results.entities[0];
|
|
912
912
|
}
|
|
913
913
|
if (core.Is.empty(entity$1)) {
|
|
914
|
-
throw new core.NotFoundError(
|
|
914
|
+
throw new core.NotFoundError(BlobStorageService.CLASS_NAME, "entityNotFound", id);
|
|
915
915
|
}
|
|
916
916
|
return core.ObjectHelper.omit(entity$1, ["userIdentity"]);
|
|
917
917
|
}
|
package/dist/esm/index.mjs
CHANGED
|
@@ -523,7 +523,7 @@ async function blobStorageList(httpRequestContext, componentName, request) {
|
|
|
523
523
|
Guards.object(ROUTES_SOURCE, "request", request);
|
|
524
524
|
const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
|
|
525
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?.
|
|
526
|
+
const result = await component.query(HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, Coerce.number(request.query?.limit), httpRequestContext.userIdentity);
|
|
527
527
|
return {
|
|
528
528
|
headers: {
|
|
529
529
|
[HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
|
|
@@ -538,15 +538,15 @@ async function blobStorageList(httpRequestContext, componentName, request) {
|
|
|
538
538
|
* Service for performing blob storage operations to a connector.
|
|
539
539
|
*/
|
|
540
540
|
class BlobStorageService {
|
|
541
|
+
/**
|
|
542
|
+
* Runtime name for the class.
|
|
543
|
+
*/
|
|
544
|
+
static CLASS_NAME = "BlobStorageService";
|
|
541
545
|
/**
|
|
542
546
|
* The namespace supported by the blob storage service.
|
|
543
547
|
* @internal
|
|
544
548
|
*/
|
|
545
549
|
static _NAMESPACE = "blob";
|
|
546
|
-
/**
|
|
547
|
-
* Runtime name for the class.
|
|
548
|
-
*/
|
|
549
|
-
CLASS_NAME = "BlobStorageService";
|
|
550
550
|
/**
|
|
551
551
|
* The namespace of the default storage connector to use.
|
|
552
552
|
* Defaults to the first entry in the factory if not provided.
|
|
@@ -580,7 +580,7 @@ class BlobStorageService {
|
|
|
580
580
|
constructor(options) {
|
|
581
581
|
const names = BlobStorageConnectorFactory.names();
|
|
582
582
|
if (names.length === 0) {
|
|
583
|
-
throw new GeneralError(
|
|
583
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "noConnectors");
|
|
584
584
|
}
|
|
585
585
|
this._entryEntityStorage = EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
|
|
586
586
|
if (Is.stringValue(options?.vaultConnectorType)) {
|
|
@@ -607,9 +607,9 @@ class BlobStorageService {
|
|
|
607
607
|
* @returns The id of the stored blob in urn format.
|
|
608
608
|
*/
|
|
609
609
|
async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
|
|
610
|
-
Guards.stringBase64(
|
|
610
|
+
Guards.stringBase64(BlobStorageService.CLASS_NAME, "blob", blob);
|
|
611
611
|
if (this._partitionPerUser) {
|
|
612
|
-
Guards.stringValue(
|
|
612
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
613
613
|
}
|
|
614
614
|
const disableEncryption = options?.disableEncryption ?? false;
|
|
615
615
|
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
@@ -632,7 +632,7 @@ class BlobStorageService {
|
|
|
632
632
|
if (Is.object(metadata)) {
|
|
633
633
|
const validationFailures = [];
|
|
634
634
|
JsonLdHelper.validate(metadata, validationFailures);
|
|
635
|
-
Validation.asValidationError(
|
|
635
|
+
Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
636
636
|
}
|
|
637
637
|
const blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;
|
|
638
638
|
if (!Is.empty(options?.compress)) {
|
|
@@ -640,9 +640,9 @@ class BlobStorageService {
|
|
|
640
640
|
}
|
|
641
641
|
// If we have a vault connector then encrypt the data.
|
|
642
642
|
if (encryptionEnabled) {
|
|
643
|
-
Guards.stringValue(
|
|
643
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
644
644
|
if (Is.empty(this._vaultConnector)) {
|
|
645
|
-
throw new GeneralError(
|
|
645
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
646
646
|
}
|
|
647
647
|
storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
|
|
648
648
|
}
|
|
@@ -669,7 +669,7 @@ class BlobStorageService {
|
|
|
669
669
|
return blobId;
|
|
670
670
|
}
|
|
671
671
|
catch (error) {
|
|
672
|
-
throw new GeneralError(
|
|
672
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "createFailed", undefined, error);
|
|
673
673
|
}
|
|
674
674
|
}
|
|
675
675
|
/**
|
|
@@ -685,12 +685,12 @@ class BlobStorageService {
|
|
|
685
685
|
* @throws Not found error if the blob cannot be found.
|
|
686
686
|
*/
|
|
687
687
|
async get(id, options, userIdentity, nodeIdentity) {
|
|
688
|
-
Urn.guard(
|
|
688
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
689
689
|
const includeContent = options?.includeContent ?? false;
|
|
690
690
|
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
691
691
|
const conditions = [];
|
|
692
692
|
if (this._partitionPerUser) {
|
|
693
|
-
Guards.stringValue(
|
|
693
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
694
694
|
conditions.push({
|
|
695
695
|
property: "userIdentity",
|
|
696
696
|
comparison: ComparisonOperator.Equals,
|
|
@@ -704,14 +704,14 @@ class BlobStorageService {
|
|
|
704
704
|
const blobStorageConnector = this.getConnector(id);
|
|
705
705
|
returnBlob = await blobStorageConnector.get(id);
|
|
706
706
|
if (Is.undefined(returnBlob)) {
|
|
707
|
-
throw new NotFoundError(
|
|
707
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
708
708
|
}
|
|
709
709
|
// If the data is encrypted then decrypt it.
|
|
710
710
|
const decryptionEnabled = blobEntry.isEncrypted && Is.stringValue(vaultKeyId);
|
|
711
711
|
if (decryptionEnabled) {
|
|
712
|
-
Guards.stringValue(
|
|
712
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
713
713
|
if (Is.empty(this._vaultConnector)) {
|
|
714
|
-
throw new GeneralError(
|
|
714
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
715
715
|
}
|
|
716
716
|
returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
|
|
717
717
|
}
|
|
@@ -723,7 +723,7 @@ class BlobStorageService {
|
|
|
723
723
|
return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
724
724
|
}
|
|
725
725
|
catch (error) {
|
|
726
|
-
throw new GeneralError(
|
|
726
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "getFailed", undefined, error);
|
|
727
727
|
}
|
|
728
728
|
}
|
|
729
729
|
/**
|
|
@@ -737,19 +737,19 @@ class BlobStorageService {
|
|
|
737
737
|
* @throws Not found error if the blob cannot be found.
|
|
738
738
|
*/
|
|
739
739
|
async update(id, encodingFormat, fileExtension, metadata, userIdentity) {
|
|
740
|
-
Urn.guard(
|
|
740
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
741
741
|
if (this._partitionPerUser) {
|
|
742
|
-
Guards.stringValue(
|
|
742
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
743
743
|
}
|
|
744
744
|
try {
|
|
745
745
|
const blobEntry = await this._entryEntityStorage.get(id);
|
|
746
746
|
if (Is.undefined(blobEntry)) {
|
|
747
|
-
throw new NotFoundError(
|
|
747
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
748
748
|
}
|
|
749
749
|
if (Is.object(metadata)) {
|
|
750
750
|
const validationFailures = [];
|
|
751
751
|
await JsonLdHelper.validate(metadata, validationFailures);
|
|
752
|
-
Validation.asValidationError(
|
|
752
|
+
Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
753
753
|
}
|
|
754
754
|
// Now store the entry in entity storage
|
|
755
755
|
const updatedBlobEntry = {
|
|
@@ -772,7 +772,7 @@ class BlobStorageService {
|
|
|
772
772
|
await this._entryEntityStorage.set(updatedBlobEntry, conditions);
|
|
773
773
|
}
|
|
774
774
|
catch (error) {
|
|
775
|
-
throw new GeneralError(
|
|
775
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "updateFailed", undefined, error);
|
|
776
776
|
}
|
|
777
777
|
}
|
|
778
778
|
/**
|
|
@@ -782,9 +782,9 @@ class BlobStorageService {
|
|
|
782
782
|
* @returns Nothing.
|
|
783
783
|
*/
|
|
784
784
|
async remove(id, userIdentity) {
|
|
785
|
-
Urn.guard(
|
|
785
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
786
786
|
if (this._partitionPerUser) {
|
|
787
|
-
Guards.stringValue(
|
|
787
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
788
788
|
}
|
|
789
789
|
try {
|
|
790
790
|
const blobStorageConnector = this.getConnector(id);
|
|
@@ -795,11 +795,11 @@ class BlobStorageService {
|
|
|
795
795
|
await this._entryEntityStorage.remove(id, conditions);
|
|
796
796
|
const removed = await blobStorageConnector.remove(id);
|
|
797
797
|
if (!removed) {
|
|
798
|
-
throw new NotFoundError(
|
|
798
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
799
799
|
}
|
|
800
800
|
}
|
|
801
801
|
catch (error) {
|
|
802
|
-
throw new GeneralError(
|
|
802
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "removeFailed", undefined, error);
|
|
803
803
|
}
|
|
804
804
|
}
|
|
805
805
|
/**
|
|
@@ -808,18 +808,18 @@ class BlobStorageService {
|
|
|
808
808
|
* @param orderBy The order for the results, defaults to created.
|
|
809
809
|
* @param orderByDirection The direction for the order, defaults to descending.
|
|
810
810
|
* @param cursor The cursor to request the next page of entries.
|
|
811
|
-
* @param
|
|
811
|
+
* @param limit The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
|
|
812
812
|
* @param userIdentity The user identity to use with storage operations.
|
|
813
813
|
* @returns All the entries for the storage matching the conditions,
|
|
814
814
|
* and a cursor which can be used to request more entities.
|
|
815
815
|
*/
|
|
816
|
-
async query(conditions, orderBy, orderByDirection, cursor,
|
|
816
|
+
async query(conditions, orderBy, orderByDirection, cursor, limit, userIdentity) {
|
|
817
817
|
const finalConditions = {
|
|
818
818
|
conditions: [],
|
|
819
819
|
logicalOperator: LogicalOperator.And
|
|
820
820
|
};
|
|
821
821
|
if (this._partitionPerUser) {
|
|
822
|
-
Guards.stringValue(
|
|
822
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
823
823
|
finalConditions.conditions.push({
|
|
824
824
|
property: "userIdentity",
|
|
825
825
|
comparison: ComparisonOperator.Equals,
|
|
@@ -836,7 +836,7 @@ class BlobStorageService {
|
|
|
836
836
|
property: orderProperty,
|
|
837
837
|
sortDirection: orderDirection
|
|
838
838
|
}
|
|
839
|
-
], undefined, cursor,
|
|
839
|
+
], undefined, cursor, limit);
|
|
840
840
|
let context = [
|
|
841
841
|
SchemaOrgContexts.ContextRoot,
|
|
842
842
|
BlobStorageContexts.ContextRoot,
|
|
@@ -865,7 +865,7 @@ class BlobStorageService {
|
|
|
865
865
|
getConnector(id) {
|
|
866
866
|
const idUri = Urn.fromValidString(id);
|
|
867
867
|
if (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {
|
|
868
|
-
throw new GeneralError(
|
|
868
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "namespaceMismatch", {
|
|
869
869
|
namespace: BlobStorageService._NAMESPACE,
|
|
870
870
|
id
|
|
871
871
|
});
|
|
@@ -883,7 +883,7 @@ class BlobStorageService {
|
|
|
883
883
|
async internalGet(id, userIdentity) {
|
|
884
884
|
const conditions = [];
|
|
885
885
|
if (this._partitionPerUser) {
|
|
886
|
-
Guards.stringValue(
|
|
886
|
+
Guards.stringValue(BlobStorageService.CLASS_NAME, "userIdentity", userIdentity);
|
|
887
887
|
conditions.push({
|
|
888
888
|
property: "userIdentity",
|
|
889
889
|
comparison: ComparisonOperator.Equals,
|
|
@@ -909,7 +909,7 @@ class BlobStorageService {
|
|
|
909
909
|
entity = results.entities[0];
|
|
910
910
|
}
|
|
911
911
|
if (Is.empty(entity)) {
|
|
912
|
-
throw new NotFoundError(
|
|
912
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "entityNotFound", id);
|
|
913
913
|
}
|
|
914
914
|
return ObjectHelper.omit(entity, ["userIdentity"]);
|
|
915
915
|
}
|
|
@@ -9,7 +9,7 @@ export declare class BlobStorageService implements IBlobStorageComponent {
|
|
|
9
9
|
/**
|
|
10
10
|
* Runtime name for the class.
|
|
11
11
|
*/
|
|
12
|
-
readonly CLASS_NAME: string;
|
|
12
|
+
static readonly CLASS_NAME: string;
|
|
13
13
|
/**
|
|
14
14
|
* Create a new instance of BlobStorageService.
|
|
15
15
|
* @param options The options for the service.
|
|
@@ -77,10 +77,10 @@ export declare class BlobStorageService implements IBlobStorageComponent {
|
|
|
77
77
|
* @param orderBy The order for the results, defaults to created.
|
|
78
78
|
* @param orderByDirection The direction for the order, defaults to descending.
|
|
79
79
|
* @param cursor The cursor to request the next page of entries.
|
|
80
|
-
* @param
|
|
80
|
+
* @param limit The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
|
|
81
81
|
* @param userIdentity The user identity to use with storage operations.
|
|
82
82
|
* @returns All the entries for the storage matching the conditions,
|
|
83
83
|
* and a cursor which can be used to request more entities.
|
|
84
84
|
*/
|
|
85
|
-
query(conditions?: EntityCondition<IBlobStorageEntry>, orderBy?: keyof Pick<IBlobStorageEntry, "dateCreated" | "dateModified">, orderByDirection?: SortDirection, cursor?: string,
|
|
85
|
+
query(conditions?: EntityCondition<IBlobStorageEntry>, orderBy?: keyof Pick<IBlobStorageEntry, "dateCreated" | "dateModified">, orderByDirection?: SortDirection, cursor?: string, limit?: number, userIdentity?: string): Promise<IBlobStorageEntryList>;
|
|
86
86
|
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @twin.org/blob-storage-service - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.2-next.5](https://github.com/twinfoundation/blob-storage/compare/blob-storage-service-v0.0.2-next.4...blob-storage-service-v0.0.2-next.5) (2025-10-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add validate-locales ([f20fcec](https://github.com/twinfoundation/blob-storage/commit/f20fceced91e39a0c9edb770b2e43ce944c92f3c))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/blob-storage-models bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @twin.org/blob-storage-connector-memory bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
18
|
+
|
|
3
19
|
## [0.0.2-next.4](https://github.com/twinfoundation/blob-storage/compare/blob-storage-service-v0.0.2-next.3...blob-storage-service-v0.0.2-next.4) (2025-10-02)
|
|
4
20
|
|
|
5
21
|
|
package/docs/open-api/spec.json
CHANGED
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"exampleResponse": {
|
|
80
80
|
"value": {
|
|
81
81
|
"name": "GeneralError",
|
|
82
|
-
"message": "
|
|
82
|
+
"message": "errorMessage",
|
|
83
83
|
"properties": {
|
|
84
84
|
"foo": "bar"
|
|
85
85
|
}
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"exampleResponse": {
|
|
101
101
|
"value": {
|
|
102
102
|
"name": "UnauthorizedError",
|
|
103
|
-
"message": "
|
|
103
|
+
"message": "errorMessage"
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"exampleResponse": {
|
|
119
119
|
"value": {
|
|
120
120
|
"name": "InternalServerError",
|
|
121
|
-
"message": "
|
|
121
|
+
"message": "errorMessage"
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -166,15 +166,12 @@
|
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
|
-
"name": "
|
|
170
|
-
"description": "
|
|
169
|
+
"name": "limit",
|
|
170
|
+
"description": "Limit the number of entities to return.",
|
|
171
171
|
"in": "query",
|
|
172
172
|
"required": false,
|
|
173
173
|
"schema": {
|
|
174
|
-
"type":
|
|
175
|
-
"number",
|
|
176
|
-
"string"
|
|
177
|
-
]
|
|
174
|
+
"type": "string"
|
|
178
175
|
}
|
|
179
176
|
},
|
|
180
177
|
{
|
|
@@ -296,7 +293,7 @@
|
|
|
296
293
|
"exampleResponse": {
|
|
297
294
|
"value": {
|
|
298
295
|
"name": "GeneralError",
|
|
299
|
-
"message": "
|
|
296
|
+
"message": "errorMessage",
|
|
300
297
|
"properties": {
|
|
301
298
|
"foo": "bar"
|
|
302
299
|
}
|
|
@@ -317,7 +314,7 @@
|
|
|
317
314
|
"exampleResponse": {
|
|
318
315
|
"value": {
|
|
319
316
|
"name": "UnauthorizedError",
|
|
320
|
-
"message": "
|
|
317
|
+
"message": "errorMessage"
|
|
321
318
|
}
|
|
322
319
|
}
|
|
323
320
|
}
|
|
@@ -335,7 +332,7 @@
|
|
|
335
332
|
"exampleResponse": {
|
|
336
333
|
"value": {
|
|
337
334
|
"name": "NotFoundError",
|
|
338
|
-
"message": "
|
|
335
|
+
"message": "errorMessage",
|
|
339
336
|
"properties": {
|
|
340
337
|
"notFoundId": "1"
|
|
341
338
|
}
|
|
@@ -356,7 +353,7 @@
|
|
|
356
353
|
"exampleResponse": {
|
|
357
354
|
"value": {
|
|
358
355
|
"name": "InternalServerError",
|
|
359
|
-
"message": "
|
|
356
|
+
"message": "errorMessage"
|
|
360
357
|
}
|
|
361
358
|
}
|
|
362
359
|
}
|
|
@@ -509,7 +506,7 @@
|
|
|
509
506
|
"exampleResponse": {
|
|
510
507
|
"value": {
|
|
511
508
|
"name": "GeneralError",
|
|
512
|
-
"message": "
|
|
509
|
+
"message": "errorMessage",
|
|
513
510
|
"properties": {
|
|
514
511
|
"foo": "bar"
|
|
515
512
|
}
|
|
@@ -530,7 +527,7 @@
|
|
|
530
527
|
"exampleResponse": {
|
|
531
528
|
"value": {
|
|
532
529
|
"name": "UnauthorizedError",
|
|
533
|
-
"message": "
|
|
530
|
+
"message": "errorMessage"
|
|
534
531
|
}
|
|
535
532
|
}
|
|
536
533
|
}
|
|
@@ -548,7 +545,7 @@
|
|
|
548
545
|
"exampleResponse": {
|
|
549
546
|
"value": {
|
|
550
547
|
"name": "NotFoundError",
|
|
551
|
-
"message": "
|
|
548
|
+
"message": "errorMessage",
|
|
552
549
|
"properties": {
|
|
553
550
|
"notFoundId": "1"
|
|
554
551
|
}
|
|
@@ -569,7 +566,7 @@
|
|
|
569
566
|
"exampleResponse": {
|
|
570
567
|
"value": {
|
|
571
568
|
"name": "InternalServerError",
|
|
572
|
-
"message": "
|
|
569
|
+
"message": "errorMessage"
|
|
573
570
|
}
|
|
574
571
|
}
|
|
575
572
|
}
|
|
@@ -639,7 +636,7 @@
|
|
|
639
636
|
"exampleResponse": {
|
|
640
637
|
"value": {
|
|
641
638
|
"name": "GeneralError",
|
|
642
|
-
"message": "
|
|
639
|
+
"message": "errorMessage",
|
|
643
640
|
"properties": {
|
|
644
641
|
"foo": "bar"
|
|
645
642
|
}
|
|
@@ -660,7 +657,7 @@
|
|
|
660
657
|
"exampleResponse": {
|
|
661
658
|
"value": {
|
|
662
659
|
"name": "UnauthorizedError",
|
|
663
|
-
"message": "
|
|
660
|
+
"message": "errorMessage"
|
|
664
661
|
}
|
|
665
662
|
}
|
|
666
663
|
}
|
|
@@ -678,7 +675,7 @@
|
|
|
678
675
|
"exampleResponse": {
|
|
679
676
|
"value": {
|
|
680
677
|
"name": "InternalServerError",
|
|
681
|
-
"message": "
|
|
678
|
+
"message": "errorMessage"
|
|
682
679
|
}
|
|
683
680
|
}
|
|
684
681
|
}
|
|
@@ -726,7 +723,7 @@
|
|
|
726
723
|
"exampleResponse": {
|
|
727
724
|
"value": {
|
|
728
725
|
"name": "GeneralError",
|
|
729
|
-
"message": "
|
|
726
|
+
"message": "errorMessage",
|
|
730
727
|
"properties": {
|
|
731
728
|
"foo": "bar"
|
|
732
729
|
}
|
|
@@ -747,7 +744,7 @@
|
|
|
747
744
|
"exampleResponse": {
|
|
748
745
|
"value": {
|
|
749
746
|
"name": "UnauthorizedError",
|
|
750
|
-
"message": "
|
|
747
|
+
"message": "errorMessage"
|
|
751
748
|
}
|
|
752
749
|
}
|
|
753
750
|
}
|
|
@@ -765,7 +762,7 @@
|
|
|
765
762
|
"exampleResponse": {
|
|
766
763
|
"value": {
|
|
767
764
|
"name": "NotFoundError",
|
|
768
|
-
"message": "
|
|
765
|
+
"message": "errorMessage",
|
|
769
766
|
"properties": {
|
|
770
767
|
"notFoundId": "1"
|
|
771
768
|
}
|
|
@@ -786,7 +783,7 @@
|
|
|
786
783
|
"exampleResponse": {
|
|
787
784
|
"value": {
|
|
788
785
|
"name": "InternalServerError",
|
|
789
|
-
"message": "
|
|
786
|
+
"message": "errorMessage"
|
|
790
787
|
}
|
|
791
788
|
}
|
|
792
789
|
}
|
|
@@ -850,7 +847,7 @@
|
|
|
850
847
|
"exampleResponse": {
|
|
851
848
|
"value": {
|
|
852
849
|
"name": "GeneralError",
|
|
853
|
-
"message": "
|
|
850
|
+
"message": "errorMessage",
|
|
854
851
|
"properties": {
|
|
855
852
|
"foo": "bar"
|
|
856
853
|
}
|
|
@@ -871,7 +868,7 @@
|
|
|
871
868
|
"exampleResponse": {
|
|
872
869
|
"value": {
|
|
873
870
|
"name": "UnauthorizedError",
|
|
874
|
-
"message": "
|
|
871
|
+
"message": "errorMessage"
|
|
875
872
|
}
|
|
876
873
|
}
|
|
877
874
|
}
|
|
@@ -889,7 +886,7 @@
|
|
|
889
886
|
"exampleResponse": {
|
|
890
887
|
"value": {
|
|
891
888
|
"name": "NotFoundError",
|
|
892
|
-
"message": "
|
|
889
|
+
"message": "errorMessage",
|
|
893
890
|
"properties": {
|
|
894
891
|
"notFoundId": "1"
|
|
895
892
|
}
|
|
@@ -910,7 +907,7 @@
|
|
|
910
907
|
"exampleResponse": {
|
|
911
908
|
"value": {
|
|
912
909
|
"name": "InternalServerError",
|
|
913
|
-
"message": "
|
|
910
|
+
"message": "errorMessage"
|
|
914
911
|
}
|
|
915
912
|
}
|
|
916
913
|
}
|
|
@@ -30,14 +30,10 @@ The options for the service.
|
|
|
30
30
|
|
|
31
31
|
### CLASS\_NAME
|
|
32
32
|
|
|
33
|
-
> `readonly` **CLASS\_NAME**: `string`
|
|
33
|
+
> `readonly` `static` **CLASS\_NAME**: `string`
|
|
34
34
|
|
|
35
35
|
Runtime name for the class.
|
|
36
36
|
|
|
37
|
-
#### Implementation of
|
|
38
|
-
|
|
39
|
-
`IBlobStorageComponent.CLASS_NAME`
|
|
40
|
-
|
|
41
37
|
## Methods
|
|
42
38
|
|
|
43
39
|
### create()
|
|
@@ -276,7 +272,7 @@ Nothing.
|
|
|
276
272
|
|
|
277
273
|
### query()
|
|
278
274
|
|
|
279
|
-
> **query**(`conditions?`, `orderBy?`, `orderByDirection?`, `cursor?`, `
|
|
275
|
+
> **query**(`conditions?`, `orderBy?`, `orderByDirection?`, `cursor?`, `limit?`, `userIdentity?`): `Promise`\<`IBlobStorageEntryList`\>
|
|
280
276
|
|
|
281
277
|
Query all the blob storage entries which match the conditions.
|
|
282
278
|
|
|
@@ -306,7 +302,7 @@ The direction for the order, defaults to descending.
|
|
|
306
302
|
|
|
307
303
|
The cursor to request the next page of entries.
|
|
308
304
|
|
|
309
|
-
#####
|
|
305
|
+
##### limit?
|
|
310
306
|
|
|
311
307
|
`number`
|
|
312
308
|
|
package/locales/en.json
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
"updateFailed": "There was a problem updating the blob",
|
|
8
8
|
"removeFailed": "There was a problem removing the blob",
|
|
9
9
|
"namespaceMismatch": "The namespace in the urn \"{id}\" does not match the namespace of the blob storage service \"{namespace}\"",
|
|
10
|
-
"vaultConnectorNotConfigured": "The vault connector is not configured, but encryption/decryption was requested."
|
|
10
|
+
"vaultConnectorNotConfigured": "The vault connector is not configured, but encryption/decryption was requested.",
|
|
11
|
+
"blobNotFound": "The blob with id \"{notFoundId}\" was not found",
|
|
12
|
+
"entityNotFound": "The entity with id \"{notFoundId}\" was not found"
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/blob-storage-service",
|
|
3
|
-
"version": "0.0.2-next.
|
|
3
|
+
"version": "0.0.2-next.5",
|
|
4
4
|
"description": "Blob storage contract implementation and REST endpoint definitions",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@twin.org/api-models": "next",
|
|
18
|
-
"@twin.org/blob-storage-models": "0.0.2-next.
|
|
18
|
+
"@twin.org/blob-storage-models": "0.0.2-next.5",
|
|
19
19
|
"@twin.org/core": "next",
|
|
20
20
|
"@twin.org/crypto": "next",
|
|
21
21
|
"@twin.org/data-json-ld": "next",
|
|
@@ -58,5 +58,9 @@
|
|
|
58
58
|
"service",
|
|
59
59
|
"microservice",
|
|
60
60
|
"business-logic"
|
|
61
|
-
]
|
|
61
|
+
],
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "git+https://github.com/twinfoundation/blob-storage/issues"
|
|
64
|
+
},
|
|
65
|
+
"homepage": "https://twindev.org"
|
|
62
66
|
}
|