@twin.org/blob-storage-connector-azure 0.0.2-next.4 → 0.0.3-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.
- package/README.md +1 -1
- package/dist/{esm/index.mjs → es/azureBlobStorageConnector.js} +51 -38
- package/dist/es/azureBlobStorageConnector.js.map +1 -0
- package/dist/es/index.js +6 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/IAzureBlobStorageConnectorConfig.js +4 -0
- package/dist/es/models/IAzureBlobStorageConnectorConfig.js.map +1 -0
- package/dist/es/models/IAzureBlobStorageConnectorConstructorOptions.js +2 -0
- package/dist/es/models/IAzureBlobStorageConnectorConstructorOptions.js.map +1 -0
- package/dist/types/azureBlobStorageConnector.d.ts +7 -2
- package/dist/types/index.d.ts +3 -3
- package/dist/types/models/IAzureBlobStorageConnectorConstructorOptions.d.ts +5 -1
- package/docs/changelog.md +33 -0
- package/docs/reference/classes/AzureBlobStorageConnector.md +19 -5
- package/docs/reference/interfaces/IAzureBlobStorageConnectorConstructorOptions.md +8 -0
- package/locales/en.json +0 -1
- package/package.json +13 -10
- package/dist/cjs/index.cjs +0 -183
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @twin.org/blob-storage-connector-azure
|
|
|
13
13
|
The tests developed are functional tests and need an instance of Azure up and running. To run Azure locally using azurite as microsoft container:
|
|
14
14
|
|
|
15
15
|
```shell
|
|
16
|
-
docker run -p
|
|
16
|
+
docker run -p 20610:10000 --name twin-blob-azure -d -e AZURITE_ACCOUNTS=testAccount:testKey mcr.microsoft.com/azure-storage/azurite azurite-blob --blobHost 0.0.0.0
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Afterwards you can run the tests as follows:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { BlobServiceClient, StorageSharedKeyCredential } from '@azure/storage-blob';
|
|
2
|
-
import { Guards, ComponentFactory, BaseError, Converter, Urn, GeneralError } from '@twin.org/core';
|
|
3
|
-
import { Sha256 } from '@twin.org/crypto';
|
|
4
|
-
|
|
5
1
|
// Copyright 2024 IOTA Stiftung.
|
|
6
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { BlobServiceClient, StorageSharedKeyCredential } from "@azure/storage-blob";
|
|
4
|
+
import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
|
|
5
|
+
import { BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, Urn } from "@twin.org/core";
|
|
6
|
+
import { Sha256 } from "@twin.org/crypto";
|
|
7
7
|
/**
|
|
8
8
|
* Class for performing blob storage operations on Azure.
|
|
9
9
|
* See https://learn.microsoft.com/en-us/azure/storage/common/storage-samples-javascript?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json for more information.
|
|
10
10
|
*/
|
|
11
|
-
class AzureBlobStorageConnector {
|
|
11
|
+
export class AzureBlobStorageConnector {
|
|
12
12
|
/**
|
|
13
13
|
* The namespace for the items.
|
|
14
14
|
*/
|
|
@@ -16,12 +16,17 @@ class AzureBlobStorageConnector {
|
|
|
16
16
|
/**
|
|
17
17
|
* Runtime name for the class.
|
|
18
18
|
*/
|
|
19
|
-
CLASS_NAME = "AzureBlobStorageConnector";
|
|
19
|
+
static CLASS_NAME = "AzureBlobStorageConnector";
|
|
20
20
|
/**
|
|
21
21
|
* The configuration for the connector.
|
|
22
22
|
* @internal
|
|
23
23
|
*/
|
|
24
24
|
_config;
|
|
25
|
+
/**
|
|
26
|
+
* The keys to use from the context ids to create partitions.
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
_partitionContextIds;
|
|
25
30
|
/**
|
|
26
31
|
* The Azure Service client.
|
|
27
32
|
* @internal
|
|
@@ -37,15 +42,23 @@ class AzureBlobStorageConnector {
|
|
|
37
42
|
* @param options The options for the connector.
|
|
38
43
|
*/
|
|
39
44
|
constructor(options) {
|
|
40
|
-
Guards.object(
|
|
41
|
-
Guards.object(
|
|
42
|
-
Guards.stringValue(
|
|
43
|
-
Guards.stringValue(
|
|
44
|
-
Guards.stringValue(
|
|
45
|
+
Guards.object(AzureBlobStorageConnector.CLASS_NAME, "options", options);
|
|
46
|
+
Guards.object(AzureBlobStorageConnector.CLASS_NAME, "options.config", options.config);
|
|
47
|
+
Guards.stringValue(AzureBlobStorageConnector.CLASS_NAME, "options.config.accountName", options.config.accountName);
|
|
48
|
+
Guards.stringValue(AzureBlobStorageConnector.CLASS_NAME, "options.config.accountKey", options.config.accountKey);
|
|
49
|
+
Guards.stringValue(AzureBlobStorageConnector.CLASS_NAME, "options.config.containerName", options.config.containerName);
|
|
45
50
|
this._config = options.config;
|
|
51
|
+
this._partitionContextIds = options.partitionContextIds;
|
|
46
52
|
this._azureBlobServiceClient = new BlobServiceClient((options.config.endpoint ?? "https://{accountName}.blob.core.windows.net/").replace("{accountName}", options.config.accountName), new StorageSharedKeyCredential(options.config.accountName, options.config.accountKey));
|
|
47
53
|
this._azureContainerClient = this._azureBlobServiceClient.getContainerClient(options.config.containerName);
|
|
48
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns the class name of the component.
|
|
57
|
+
* @returns The class name of the component.
|
|
58
|
+
*/
|
|
59
|
+
className() {
|
|
60
|
+
return AzureBlobStorageConnector.CLASS_NAME;
|
|
61
|
+
}
|
|
49
62
|
/**
|
|
50
63
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
51
64
|
* @param nodeLoggingComponentType The node logging component type.
|
|
@@ -54,19 +67,11 @@ class AzureBlobStorageConnector {
|
|
|
54
67
|
async bootstrap(nodeLoggingComponentType) {
|
|
55
68
|
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
56
69
|
try {
|
|
57
|
-
await nodeLogging?.log({
|
|
58
|
-
level: "info",
|
|
59
|
-
source: this.CLASS_NAME,
|
|
60
|
-
message: "containerCreating",
|
|
61
|
-
data: {
|
|
62
|
-
container: this._config.containerName
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
70
|
const exists = await this._azureContainerClient.exists();
|
|
66
71
|
if (exists) {
|
|
67
72
|
await nodeLogging?.log({
|
|
68
73
|
level: "info",
|
|
69
|
-
source:
|
|
74
|
+
source: AzureBlobStorageConnector.CLASS_NAME,
|
|
70
75
|
message: "containerExists",
|
|
71
76
|
data: {
|
|
72
77
|
container: this._config.containerName
|
|
@@ -74,21 +79,21 @@ class AzureBlobStorageConnector {
|
|
|
74
79
|
});
|
|
75
80
|
}
|
|
76
81
|
else {
|
|
77
|
-
await this._azureContainerClient.create();
|
|
78
82
|
await nodeLogging?.log({
|
|
79
83
|
level: "info",
|
|
80
|
-
source:
|
|
81
|
-
message: "
|
|
84
|
+
source: AzureBlobStorageConnector.CLASS_NAME,
|
|
85
|
+
message: "containerCreating",
|
|
82
86
|
data: {
|
|
83
87
|
container: this._config.containerName
|
|
84
88
|
}
|
|
85
89
|
});
|
|
90
|
+
await this._azureContainerClient.create();
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
93
|
catch (err) {
|
|
89
94
|
await nodeLogging?.log({
|
|
90
95
|
level: "error",
|
|
91
|
-
source:
|
|
96
|
+
source: AzureBlobStorageConnector.CLASS_NAME,
|
|
92
97
|
message: "containerCreateFailed",
|
|
93
98
|
data: {
|
|
94
99
|
container: this._config.containerName
|
|
@@ -105,15 +110,17 @@ class AzureBlobStorageConnector {
|
|
|
105
110
|
* @returns The id of the stored blob in urn format.
|
|
106
111
|
*/
|
|
107
112
|
async set(blob) {
|
|
108
|
-
Guards.uint8Array(
|
|
113
|
+
Guards.uint8Array(AzureBlobStorageConnector.CLASS_NAME, "blob", blob);
|
|
114
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
115
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
109
116
|
try {
|
|
110
117
|
const id = Converter.bytesToHex(Sha256.sum256(blob));
|
|
111
|
-
const blockBlobClient = this._azureContainerClient.getBlockBlobClient(id);
|
|
118
|
+
const blockBlobClient = this._azureContainerClient.getBlockBlobClient(`${partitionKey ?? "root"}/${id}`);
|
|
112
119
|
await blockBlobClient.uploadData(blob);
|
|
113
120
|
return `blob:${new Urn(AzureBlobStorageConnector.NAMESPACE, id).toString()}`;
|
|
114
121
|
}
|
|
115
122
|
catch (err) {
|
|
116
|
-
throw new GeneralError(
|
|
123
|
+
throw new GeneralError(AzureBlobStorageConnector.CLASS_NAME, "setBlobFailed", undefined, err);
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
/**
|
|
@@ -122,22 +129,27 @@ class AzureBlobStorageConnector {
|
|
|
122
129
|
* @returns The data for the blob if it can be found or undefined.
|
|
123
130
|
*/
|
|
124
131
|
async get(id) {
|
|
125
|
-
Urn.guard(
|
|
132
|
+
Urn.guard(AzureBlobStorageConnector.CLASS_NAME, "id", id);
|
|
126
133
|
const urnParsed = Urn.fromValidString(id);
|
|
134
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
135
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
127
136
|
if (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {
|
|
128
|
-
throw new GeneralError(
|
|
137
|
+
throw new GeneralError(AzureBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
129
138
|
namespace: AzureBlobStorageConnector.NAMESPACE,
|
|
130
139
|
id
|
|
131
140
|
});
|
|
132
141
|
}
|
|
133
142
|
try {
|
|
134
143
|
const key = urnParsed.namespaceSpecific(1);
|
|
135
|
-
const blobClient = this._azureContainerClient.getBlobClient(key);
|
|
144
|
+
const blobClient = this._azureContainerClient.getBlobClient(`${partitionKey ?? "root"}/${key}`);
|
|
136
145
|
const buffer = await blobClient.downloadToBuffer();
|
|
137
146
|
return new Uint8Array(buffer);
|
|
138
147
|
}
|
|
139
148
|
catch (err) {
|
|
140
|
-
|
|
149
|
+
if (Is.object(err) && err.statusCode === 404) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
throw new GeneralError(AzureBlobStorageConnector.CLASS_NAME, "getBlobFailed", {
|
|
141
153
|
id,
|
|
142
154
|
namespace: AzureBlobStorageConnector.NAMESPACE
|
|
143
155
|
}, err);
|
|
@@ -149,17 +161,19 @@ class AzureBlobStorageConnector {
|
|
|
149
161
|
* @returns True if the blob was found.
|
|
150
162
|
*/
|
|
151
163
|
async remove(id) {
|
|
152
|
-
Urn.guard(
|
|
164
|
+
Urn.guard(AzureBlobStorageConnector.CLASS_NAME, "id", id);
|
|
153
165
|
const urnParsed = Urn.fromValidString(id);
|
|
166
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
167
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
154
168
|
if (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {
|
|
155
|
-
throw new GeneralError(
|
|
169
|
+
throw new GeneralError(AzureBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
156
170
|
namespace: AzureBlobStorageConnector.NAMESPACE,
|
|
157
171
|
id
|
|
158
172
|
});
|
|
159
173
|
}
|
|
160
174
|
try {
|
|
161
175
|
const key = urnParsed.namespaceSpecific(1);
|
|
162
|
-
const blockBlobClient =
|
|
176
|
+
const blockBlobClient = this._azureContainerClient.getBlockBlobClient(`${partitionKey ?? "root"}/${key}`);
|
|
163
177
|
const options = {
|
|
164
178
|
deleteSnapshots: "include"
|
|
165
179
|
};
|
|
@@ -170,12 +184,11 @@ class AzureBlobStorageConnector {
|
|
|
170
184
|
return false;
|
|
171
185
|
}
|
|
172
186
|
catch (err) {
|
|
173
|
-
if (err
|
|
187
|
+
if (Is.object(err) && err.statusCode === 404) {
|
|
174
188
|
return false;
|
|
175
189
|
}
|
|
176
|
-
throw new GeneralError(
|
|
190
|
+
throw new GeneralError(AzureBlobStorageConnector.CLASS_NAME, "removeBlobFailed", { id }, err);
|
|
177
191
|
}
|
|
178
192
|
}
|
|
179
193
|
}
|
|
180
|
-
|
|
181
|
-
export { AzureBlobStorageConnector };
|
|
194
|
+
//# sourceMappingURL=azureBlobStorageConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azureBlobStorageConnector.js","sourceRoot":"","sources":["../../src/azureBlobStorageConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\ttype BlobClient,\n\ttype BlobDeleteOptions,\n\ttype BlobDeleteResponse,\n\tBlobServiceClient,\n\ttype BlockBlobClient,\n\ttype ContainerClient,\n\tStorageSharedKeyCredential\n} from \"@azure/storage-blob\";\nimport type { IBlobStorageConnector } from \"@twin.org/blob-storage-models\";\nimport { ContextIdHelper, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tUrn\n} from \"@twin.org/core\";\nimport { Sha256 } from \"@twin.org/crypto\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { IAzureBlobStorageConnectorConfig } from \"./models/IAzureBlobStorageConnectorConfig.js\";\nimport type { IAzureBlobStorageConnectorConstructorOptions } from \"./models/IAzureBlobStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing blob storage operations on Azure.\n * See https://learn.microsoft.com/en-us/azure/storage/common/storage-samples-javascript?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json for more information.\n */\nexport class AzureBlobStorageConnector implements IBlobStorageConnector {\n\t/**\n\t * The namespace for the items.\n\t */\n\tpublic static readonly NAMESPACE: string = \"azure\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<AzureBlobStorageConnector>();\n\n\t/**\n\t * The configuration for the connector.\n\t * @internal\n\t */\n\tprivate readonly _config: IAzureBlobStorageConnectorConfig;\n\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t * @internal\n\t */\n\tprivate readonly _partitionContextIds?: string[];\n\n\t/**\n\t * The Azure Service client.\n\t * @internal\n\t */\n\tprivate readonly _azureBlobServiceClient: BlobServiceClient;\n\n\t/**\n\t * The Azure Container client.\n\t * @internal\n\t */\n\tprivate readonly _azureContainerClient: ContainerClient;\n\n\t/**\n\t * Create a new instance of AzureBlobStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IAzureBlobStorageConnectorConstructorOptions) {\n\t\tGuards.object(AzureBlobStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.object<IAzureBlobStorageConnectorConfig>(\n\t\t\tAzureBlobStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config),\n\t\t\toptions.config\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAzureBlobStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.accountName),\n\t\t\toptions.config.accountName\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAzureBlobStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.accountKey),\n\t\t\toptions.config.accountKey\n\t\t);\n\t\tGuards.stringValue(\n\t\t\tAzureBlobStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.containerName),\n\t\t\toptions.config.containerName\n\t\t);\n\n\t\tthis._config = options.config;\n\t\tthis._partitionContextIds = options.partitionContextIds;\n\n\t\tthis._azureBlobServiceClient = new BlobServiceClient(\n\t\t\t(options.config.endpoint ?? \"https://{accountName}.blob.core.windows.net/\").replace(\n\t\t\t\t\"{accountName}\",\n\t\t\t\toptions.config.accountName\n\t\t\t),\n\t\t\tnew StorageSharedKeyCredential(options.config.accountName, options.config.accountKey)\n\t\t);\n\n\t\tthis._azureContainerClient = this._azureBlobServiceClient.getContainerClient(\n\t\t\toptions.config.containerName\n\t\t);\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn AzureBlobStorageConnector.CLASS_NAME;\n\t}\n\n\t/**\n\t * Bootstrap the component by creating and initializing any resources it needs.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns True if the bootstrapping process was successful.\n\t */\n\tpublic async bootstrap(nodeLoggingComponentType?: string): Promise<boolean> {\n\t\tconst nodeLogging = ComponentFactory.getIfExists<ILoggingComponent>(nodeLoggingComponentType);\n\n\t\ttry {\n\t\t\tconst exists = await this._azureContainerClient.exists();\n\n\t\t\tif (exists) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: AzureBlobStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"containerExists\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcontainer: this._config.containerName\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: AzureBlobStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"containerCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcontainer: this._config.containerName\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait this._azureContainerClient.create();\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"error\",\n\t\t\t\tsource: AzureBlobStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"containerCreateFailed\",\n\t\t\t\tdata: {\n\t\t\t\t\tcontainer: this._config.containerName\n\t\t\t\t},\n\t\t\t\terror: BaseError.fromError(err)\n\t\t\t});\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Set the blob.\n\t * @param blob The data for the blob.\n\t * @returns The id of the stored blob in urn format.\n\t */\n\tpublic async set(blob: Uint8Array): Promise<string> {\n\t\tGuards.uint8Array(AzureBlobStorageConnector.CLASS_NAME, nameof(blob), blob);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\ttry {\n\t\t\tconst id = Converter.bytesToHex(Sha256.sum256(blob));\n\t\t\tconst blockBlobClient: BlockBlobClient = this._azureContainerClient.getBlockBlobClient(\n\t\t\t\t`${partitionKey ?? \"root\"}/${id}`\n\t\t\t);\n\t\t\tawait blockBlobClient.uploadData(blob);\n\n\t\t\treturn `blob:${new Urn(AzureBlobStorageConnector.NAMESPACE, id).toString()}`;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(AzureBlobStorageConnector.CLASS_NAME, \"setBlobFailed\", undefined, err);\n\t\t}\n\t}\n\n\t/**\n\t * Get the blob.\n\t * @param id The id of the blob to get in urn format.\n\t * @returns The data for the blob if it can be found or undefined.\n\t */\n\tpublic async get(id: string): Promise<Uint8Array | undefined> {\n\t\tUrn.guard(AzureBlobStorageConnector.CLASS_NAME, nameof(id), id);\n\t\tconst urnParsed = Urn.fromValidString(id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tif (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {\n\t\t\tthrow new GeneralError(AzureBlobStorageConnector.CLASS_NAME, \"namespaceMismatch\", {\n\t\t\t\tnamespace: AzureBlobStorageConnector.NAMESPACE,\n\t\t\t\tid\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tconst key = urnParsed.namespaceSpecific(1);\n\t\t\tconst blobClient: BlobClient = this._azureContainerClient.getBlobClient(\n\t\t\t\t`${partitionKey ?? \"root\"}/${key}`\n\t\t\t);\n\t\t\tconst buffer = await blobClient.downloadToBuffer();\n\t\t\treturn new Uint8Array(buffer);\n\t\t} catch (err) {\n\t\t\tif (Is.object<{ statusCode: number }>(err) && err.statusCode === 404) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new GeneralError(\n\t\t\t\tAzureBlobStorageConnector.CLASS_NAME,\n\t\t\t\t\"getBlobFailed\",\n\t\t\t\t{\n\t\t\t\t\tid,\n\t\t\t\t\tnamespace: AzureBlobStorageConnector.NAMESPACE\n\t\t\t\t},\n\t\t\t\terr\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Remove the blob.\n\t * @param id The id of the blob to remove in urn format.\n\t * @returns True if the blob was found.\n\t */\n\tpublic async remove(id: string): Promise<boolean> {\n\t\tUrn.guard(AzureBlobStorageConnector.CLASS_NAME, nameof(id), id);\n\t\tconst urnParsed = Urn.fromValidString(id);\n\n\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\tconst partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);\n\n\t\tif (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {\n\t\t\tthrow new GeneralError(AzureBlobStorageConnector.CLASS_NAME, \"namespaceMismatch\", {\n\t\t\t\tnamespace: AzureBlobStorageConnector.NAMESPACE,\n\t\t\t\tid\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tconst key = urnParsed.namespaceSpecific(1);\n\n\t\t\tconst blockBlobClient: BlockBlobClient = this._azureContainerClient.getBlockBlobClient(\n\t\t\t\t`${partitionKey ?? \"root\"}/${key}`\n\t\t\t);\n\n\t\t\tconst options: BlobDeleteOptions = {\n\t\t\t\tdeleteSnapshots: \"include\"\n\t\t\t};\n\t\t\tconst blobDeleteResponse: BlobDeleteResponse = await blockBlobClient.delete(options);\n\n\t\t\tif (!blobDeleteResponse.errorCode) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t} catch (err) {\n\t\t\tif (Is.object<{ statusCode: number }>(err) && err.statusCode === 404) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrow new GeneralError(AzureBlobStorageConnector.CLASS_NAME, \"removeBlobFailed\", { id }, err);\n\t\t}\n\t}\n}\n"]}
|
package/dist/es/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
export * from "./azureBlobStorageConnector.js";
|
|
4
|
+
export * from "./models/IAzureBlobStorageConnectorConfig.js";
|
|
5
|
+
export * from "./models/IAzureBlobStorageConnectorConstructorOptions.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./azureBlobStorageConnector.js\";\nexport * from \"./models/IAzureBlobStorageConnectorConfig.js\";\nexport * from \"./models/IAzureBlobStorageConnectorConstructorOptions.js\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IAzureBlobStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IAzureBlobStorageConnectorConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Configuration for the Azure Blob Storage Connector.\n */\nexport interface IAzureBlobStorageConnectorConfig {\n\t/**\n\t * Storage account name.\n\t */\n\taccountName: string;\n\n\t/**\n\t * Account key.\n\t */\n\taccountKey: string;\n\n\t/**\n\t * The Azure container name.\n\t */\n\tcontainerName: string;\n\n\t/**\n\t * Endpoint defaults to `https://{accountName}.blob.core.windows.net/` where accountName will be\n\t * substituted.\n\t */\n\tendpoint?: string;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IAzureBlobStorageConnectorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IAzureBlobStorageConnectorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IAzureBlobStorageConnectorConfig } from \"./IAzureBlobStorageConnectorConfig.js\";\n\n/**\n * Options for the Azure Blob Storage Connector constructor.\n */\nexport interface IAzureBlobStorageConnectorConstructorOptions {\n\t/**\n\t * The keys to use from the context ids to create partitions.\n\t */\n\tpartitionContextIds?: string[];\n\n\t/**\n\t * The configuration for the connector.\n\t */\n\tconfig: IAzureBlobStorageConnectorConfig;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IBlobStorageConnector } from "@twin.org/blob-storage-models";
|
|
2
|
-
import type { IAzureBlobStorageConnectorConstructorOptions } from "./models/IAzureBlobStorageConnectorConstructorOptions";
|
|
2
|
+
import type { IAzureBlobStorageConnectorConstructorOptions } from "./models/IAzureBlobStorageConnectorConstructorOptions.js";
|
|
3
3
|
/**
|
|
4
4
|
* Class for performing blob storage operations on Azure.
|
|
5
5
|
* See https://learn.microsoft.com/en-us/azure/storage/common/storage-samples-javascript?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json for more information.
|
|
@@ -12,12 +12,17 @@ export declare class AzureBlobStorageConnector implements IBlobStorageConnector
|
|
|
12
12
|
/**
|
|
13
13
|
* Runtime name for the class.
|
|
14
14
|
*/
|
|
15
|
-
readonly CLASS_NAME: string;
|
|
15
|
+
static readonly CLASS_NAME: string;
|
|
16
16
|
/**
|
|
17
17
|
* Create a new instance of AzureBlobStorageConnector.
|
|
18
18
|
* @param options The options for the connector.
|
|
19
19
|
*/
|
|
20
20
|
constructor(options: IAzureBlobStorageConnectorConstructorOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Returns the class name of the component.
|
|
23
|
+
* @returns The class name of the component.
|
|
24
|
+
*/
|
|
25
|
+
className(): string;
|
|
21
26
|
/**
|
|
22
27
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
23
28
|
* @param nodeLoggingComponentType The node logging component type.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from "./azureBlobStorageConnector";
|
|
2
|
-
export * from "./models/IAzureBlobStorageConnectorConfig";
|
|
3
|
-
export * from "./models/IAzureBlobStorageConnectorConstructorOptions";
|
|
1
|
+
export * from "./azureBlobStorageConnector.js";
|
|
2
|
+
export * from "./models/IAzureBlobStorageConnectorConfig.js";
|
|
3
|
+
export * from "./models/IAzureBlobStorageConnectorConstructorOptions.js";
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import type { IAzureBlobStorageConnectorConfig } from "./IAzureBlobStorageConnectorConfig";
|
|
1
|
+
import type { IAzureBlobStorageConnectorConfig } from "./IAzureBlobStorageConnectorConfig.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for the Azure Blob Storage Connector constructor.
|
|
4
4
|
*/
|
|
5
5
|
export interface IAzureBlobStorageConnectorConstructorOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The keys to use from the context ids to create partitions.
|
|
8
|
+
*/
|
|
9
|
+
partitionContextIds?: string[];
|
|
6
10
|
/**
|
|
7
11
|
* The configuration for the connector.
|
|
8
12
|
*/
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @twin.org/blob-storage-connector-azure - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.1](https://github.com/twinfoundation/blob-storage/compare/blob-storage-connector-azure-v0.0.3-next.0...blob-storage-connector-azure-v0.0.3-next.1) (2025-11-11)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add context id features ([#30](https://github.com/twinfoundation/blob-storage/issues/30)) ([fbf1c92](https://github.com/twinfoundation/blob-storage/commit/fbf1c9276424c841ef5ef3f4de8469ab3fba7e9c))
|
|
9
|
+
* add validate-locales ([f20fcec](https://github.com/twinfoundation/blob-storage/commit/f20fceced91e39a0c9edb770b2e43ce944c92f3c))
|
|
10
|
+
* eslint migration to flat config ([e4239dd](https://github.com/twinfoundation/blob-storage/commit/e4239dd1c721955cff7f0357255d2bba15319972))
|
|
11
|
+
* update dependencies ([56f0094](https://github.com/twinfoundation/blob-storage/commit/56f0094b68d8bd22864cd899ac1b61d95540f719))
|
|
12
|
+
* update framework core ([ff339fe](https://github.com/twinfoundation/blob-storage/commit/ff339fe7e3f09ddff429907834bdf43617e9c05e))
|
|
13
|
+
* use shared store mechanism ([#12](https://github.com/twinfoundation/blob-storage/issues/12)) ([cae8110](https://github.com/twinfoundation/blob-storage/commit/cae8110681847a1ac4fcac968b8196694e49c320))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Dependencies
|
|
17
|
+
|
|
18
|
+
* The following workspace dependencies were updated
|
|
19
|
+
* dependencies
|
|
20
|
+
* @twin.org/blob-storage-models bumped from 0.0.3-next.0 to 0.0.3-next.1
|
|
21
|
+
|
|
22
|
+
## [0.0.2-next.5](https://github.com/twinfoundation/blob-storage/compare/blob-storage-connector-azure-v0.0.2-next.4...blob-storage-connector-azure-v0.0.2-next.5) (2025-10-09)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* add validate-locales ([f20fcec](https://github.com/twinfoundation/blob-storage/commit/f20fceced91e39a0c9edb770b2e43ce944c92f3c))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Dependencies
|
|
31
|
+
|
|
32
|
+
* The following workspace dependencies were updated
|
|
33
|
+
* dependencies
|
|
34
|
+
* @twin.org/blob-storage-models bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
35
|
+
|
|
3
36
|
## [0.0.2-next.4](https://github.com/twinfoundation/blob-storage/compare/blob-storage-connector-azure-v0.0.2-next.3...blob-storage-connector-azure-v0.0.2-next.4) (2025-10-02)
|
|
4
37
|
|
|
5
38
|
|
|
@@ -39,15 +39,29 @@ The namespace for the items.
|
|
|
39
39
|
|
|
40
40
|
### CLASS\_NAME
|
|
41
41
|
|
|
42
|
-
> `readonly` **CLASS\_NAME**: `string`
|
|
42
|
+
> `readonly` `static` **CLASS\_NAME**: `string`
|
|
43
43
|
|
|
44
44
|
Runtime name for the class.
|
|
45
45
|
|
|
46
|
+
## Methods
|
|
47
|
+
|
|
48
|
+
### className()
|
|
49
|
+
|
|
50
|
+
> **className**(): `string`
|
|
51
|
+
|
|
52
|
+
Returns the class name of the component.
|
|
53
|
+
|
|
54
|
+
#### Returns
|
|
55
|
+
|
|
56
|
+
`string`
|
|
57
|
+
|
|
58
|
+
The class name of the component.
|
|
59
|
+
|
|
46
60
|
#### Implementation of
|
|
47
61
|
|
|
48
|
-
`IBlobStorageConnector.
|
|
62
|
+
`IBlobStorageConnector.className`
|
|
49
63
|
|
|
50
|
-
|
|
64
|
+
***
|
|
51
65
|
|
|
52
66
|
### bootstrap()
|
|
53
67
|
|
|
@@ -103,7 +117,7 @@ The id of the stored blob in urn format.
|
|
|
103
117
|
|
|
104
118
|
### get()
|
|
105
119
|
|
|
106
|
-
> **get**(`id`): `Promise`\<`
|
|
120
|
+
> **get**(`id`): `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
107
121
|
|
|
108
122
|
Get the blob.
|
|
109
123
|
|
|
@@ -117,7 +131,7 @@ The id of the blob to get in urn format.
|
|
|
117
131
|
|
|
118
132
|
#### Returns
|
|
119
133
|
|
|
120
|
-
`Promise`\<`
|
|
134
|
+
`Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
121
135
|
|
|
122
136
|
The data for the blob if it can be found or undefined.
|
|
123
137
|
|
|
@@ -4,6 +4,14 @@ Options for the Azure Blob Storage Connector constructor.
|
|
|
4
4
|
|
|
5
5
|
## Properties
|
|
6
6
|
|
|
7
|
+
### partitionContextIds?
|
|
8
|
+
|
|
9
|
+
> `optional` **partitionContextIds**: `string`[]
|
|
10
|
+
|
|
11
|
+
The keys to use from the context ids to create partitions.
|
|
12
|
+
|
|
13
|
+
***
|
|
14
|
+
|
|
7
15
|
### config
|
|
8
16
|
|
|
9
17
|
> **config**: [`IAzureBlobStorageConnectorConfig`](IAzureBlobStorageConnectorConfig.md)
|
package/locales/en.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/blob-storage-connector-azure",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-next.1",
|
|
4
4
|
"description": "Blob Storage connector implementation using Azure",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,27 +14,26 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@azure/storage-blob": "12.
|
|
18
|
-
"@twin.org/blob-storage-models": "0.0.
|
|
17
|
+
"@azure/storage-blob": "12.29.1",
|
|
18
|
+
"@twin.org/blob-storage-models": "0.0.3-next.1",
|
|
19
|
+
"@twin.org/context": "next",
|
|
19
20
|
"@twin.org/core": "next",
|
|
20
21
|
"@twin.org/crypto": "next",
|
|
21
22
|
"@twin.org/logging-models": "next",
|
|
22
23
|
"@twin.org/nameof": "next"
|
|
23
24
|
},
|
|
24
|
-
"main": "./dist/
|
|
25
|
-
"module": "./dist/esm/index.mjs",
|
|
25
|
+
"main": "./dist/es/index.js",
|
|
26
26
|
"types": "./dist/types/index.d.ts",
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|
|
29
29
|
"types": "./dist/types/index.d.ts",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
30
|
+
"import": "./dist/es/index.js",
|
|
31
|
+
"default": "./dist/es/index.js"
|
|
32
32
|
},
|
|
33
33
|
"./locales/*.json": "./locales/*.json"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
|
-
"dist/
|
|
37
|
-
"dist/esm",
|
|
36
|
+
"dist/es",
|
|
38
37
|
"dist/types",
|
|
39
38
|
"locales",
|
|
40
39
|
"docs"
|
|
@@ -53,5 +52,9 @@
|
|
|
53
52
|
"connector",
|
|
54
53
|
"adapter",
|
|
55
54
|
"integration"
|
|
56
|
-
]
|
|
55
|
+
],
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "git+https://github.com/twinfoundation/blob-storage/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://twindev.org"
|
|
57
60
|
}
|
package/dist/cjs/index.cjs
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var storageBlob = require('@azure/storage-blob');
|
|
4
|
-
var core = require('@twin.org/core');
|
|
5
|
-
var crypto = require('@twin.org/crypto');
|
|
6
|
-
|
|
7
|
-
// Copyright 2024 IOTA Stiftung.
|
|
8
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
9
|
-
/**
|
|
10
|
-
* Class for performing blob storage operations on Azure.
|
|
11
|
-
* See https://learn.microsoft.com/en-us/azure/storage/common/storage-samples-javascript?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json for more information.
|
|
12
|
-
*/
|
|
13
|
-
class AzureBlobStorageConnector {
|
|
14
|
-
/**
|
|
15
|
-
* The namespace for the items.
|
|
16
|
-
*/
|
|
17
|
-
static NAMESPACE = "azure";
|
|
18
|
-
/**
|
|
19
|
-
* Runtime name for the class.
|
|
20
|
-
*/
|
|
21
|
-
CLASS_NAME = "AzureBlobStorageConnector";
|
|
22
|
-
/**
|
|
23
|
-
* The configuration for the connector.
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
_config;
|
|
27
|
-
/**
|
|
28
|
-
* The Azure Service client.
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
_azureBlobServiceClient;
|
|
32
|
-
/**
|
|
33
|
-
* The Azure Container client.
|
|
34
|
-
* @internal
|
|
35
|
-
*/
|
|
36
|
-
_azureContainerClient;
|
|
37
|
-
/**
|
|
38
|
-
* Create a new instance of AzureBlobStorageConnector.
|
|
39
|
-
* @param options The options for the connector.
|
|
40
|
-
*/
|
|
41
|
-
constructor(options) {
|
|
42
|
-
core.Guards.object(this.CLASS_NAME, "options", options);
|
|
43
|
-
core.Guards.object(this.CLASS_NAME, "options.config", options.config);
|
|
44
|
-
core.Guards.stringValue(this.CLASS_NAME, "options.config.accountName", options.config.accountName);
|
|
45
|
-
core.Guards.stringValue(this.CLASS_NAME, "options.config.accountKey", options.config.accountKey);
|
|
46
|
-
core.Guards.stringValue(this.CLASS_NAME, "options.config.containerName", options.config.containerName);
|
|
47
|
-
this._config = options.config;
|
|
48
|
-
this._azureBlobServiceClient = new storageBlob.BlobServiceClient((options.config.endpoint ?? "https://{accountName}.blob.core.windows.net/").replace("{accountName}", options.config.accountName), new storageBlob.StorageSharedKeyCredential(options.config.accountName, options.config.accountKey));
|
|
49
|
-
this._azureContainerClient = this._azureBlobServiceClient.getContainerClient(options.config.containerName);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Bootstrap the component by creating and initializing any resources it needs.
|
|
53
|
-
* @param nodeLoggingComponentType The node logging component type.
|
|
54
|
-
* @returns True if the bootstrapping process was successful.
|
|
55
|
-
*/
|
|
56
|
-
async bootstrap(nodeLoggingComponentType) {
|
|
57
|
-
const nodeLogging = core.ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
58
|
-
try {
|
|
59
|
-
await nodeLogging?.log({
|
|
60
|
-
level: "info",
|
|
61
|
-
source: this.CLASS_NAME,
|
|
62
|
-
message: "containerCreating",
|
|
63
|
-
data: {
|
|
64
|
-
container: this._config.containerName
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
const exists = await this._azureContainerClient.exists();
|
|
68
|
-
if (exists) {
|
|
69
|
-
await nodeLogging?.log({
|
|
70
|
-
level: "info",
|
|
71
|
-
source: this.CLASS_NAME,
|
|
72
|
-
message: "containerExists",
|
|
73
|
-
data: {
|
|
74
|
-
container: this._config.containerName
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
await this._azureContainerClient.create();
|
|
80
|
-
await nodeLogging?.log({
|
|
81
|
-
level: "info",
|
|
82
|
-
source: this.CLASS_NAME,
|
|
83
|
-
message: "containerCreated",
|
|
84
|
-
data: {
|
|
85
|
-
container: this._config.containerName
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
await nodeLogging?.log({
|
|
92
|
-
level: "error",
|
|
93
|
-
source: this.CLASS_NAME,
|
|
94
|
-
message: "containerCreateFailed",
|
|
95
|
-
data: {
|
|
96
|
-
container: this._config.containerName
|
|
97
|
-
},
|
|
98
|
-
error: core.BaseError.fromError(err)
|
|
99
|
-
});
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Set the blob.
|
|
106
|
-
* @param blob The data for the blob.
|
|
107
|
-
* @returns The id of the stored blob in urn format.
|
|
108
|
-
*/
|
|
109
|
-
async set(blob) {
|
|
110
|
-
core.Guards.uint8Array(this.CLASS_NAME, "blob", blob);
|
|
111
|
-
try {
|
|
112
|
-
const id = core.Converter.bytesToHex(crypto.Sha256.sum256(blob));
|
|
113
|
-
const blockBlobClient = this._azureContainerClient.getBlockBlobClient(id);
|
|
114
|
-
await blockBlobClient.uploadData(blob);
|
|
115
|
-
return `blob:${new core.Urn(AzureBlobStorageConnector.NAMESPACE, id).toString()}`;
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
throw new core.GeneralError(this.CLASS_NAME, "setBlobFailed", undefined, err);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Get the blob.
|
|
123
|
-
* @param id The id of the blob to get in urn format.
|
|
124
|
-
* @returns The data for the blob if it can be found or undefined.
|
|
125
|
-
*/
|
|
126
|
-
async get(id) {
|
|
127
|
-
core.Urn.guard(this.CLASS_NAME, "id", id);
|
|
128
|
-
const urnParsed = core.Urn.fromValidString(id);
|
|
129
|
-
if (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {
|
|
130
|
-
throw new core.GeneralError(this.CLASS_NAME, "namespaceMismatch", {
|
|
131
|
-
namespace: AzureBlobStorageConnector.NAMESPACE,
|
|
132
|
-
id
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
try {
|
|
136
|
-
const key = urnParsed.namespaceSpecific(1);
|
|
137
|
-
const blobClient = this._azureContainerClient.getBlobClient(key);
|
|
138
|
-
const buffer = await blobClient.downloadToBuffer();
|
|
139
|
-
return new Uint8Array(buffer);
|
|
140
|
-
}
|
|
141
|
-
catch (err) {
|
|
142
|
-
throw new core.GeneralError(this.CLASS_NAME, "getBlobFailed", {
|
|
143
|
-
id,
|
|
144
|
-
namespace: AzureBlobStorageConnector.NAMESPACE
|
|
145
|
-
}, err);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Remove the blob.
|
|
150
|
-
* @param id The id of the blob to remove in urn format.
|
|
151
|
-
* @returns True if the blob was found.
|
|
152
|
-
*/
|
|
153
|
-
async remove(id) {
|
|
154
|
-
core.Urn.guard(this.CLASS_NAME, "id", id);
|
|
155
|
-
const urnParsed = core.Urn.fromValidString(id);
|
|
156
|
-
if (urnParsed.namespaceMethod() !== AzureBlobStorageConnector.NAMESPACE) {
|
|
157
|
-
throw new core.GeneralError(this.CLASS_NAME, "namespaceMismatch", {
|
|
158
|
-
namespace: AzureBlobStorageConnector.NAMESPACE,
|
|
159
|
-
id
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
const key = urnParsed.namespaceSpecific(1);
|
|
164
|
-
const blockBlobClient = await this._azureContainerClient.getBlockBlobClient(key);
|
|
165
|
-
const options = {
|
|
166
|
-
deleteSnapshots: "include"
|
|
167
|
-
};
|
|
168
|
-
const blobDeleteResponse = await blockBlobClient.delete(options);
|
|
169
|
-
if (!blobDeleteResponse.errorCode) {
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
catch (err) {
|
|
175
|
-
if (err instanceof Error && "statusCode" in err && err.statusCode === 404) {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
throw new core.GeneralError(this.CLASS_NAME, "removeBlobFailed", { id }, err);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
exports.AzureBlobStorageConnector = AzureBlobStorageConnector;
|