@twin.org/blob-storage-connector-file 0.0.2-next.5 → 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/dist/{esm/index.mjs → es/fileBlobStorageConnector.js} +46 -24
- package/dist/es/fileBlobStorageConnector.js.map +1 -0
- package/dist/es/index.js +6 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/IFileBlobStorageConnectorConfig.js +4 -0
- package/dist/es/models/IFileBlobStorageConnectorConfig.js.map +1 -0
- package/dist/es/models/IFileBlobStorageConnectorConstructorOptions.js +2 -0
- package/dist/es/models/IFileBlobStorageConnectorConstructorOptions.js.map +1 -0
- package/dist/types/fileBlobStorageConnector.d.ts +6 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/models/IFileBlobStorageConnectorConstructorOptions.d.ts +5 -1
- package/docs/changelog.md +19 -0
- package/docs/reference/classes/FileBlobStorageConnector.md +20 -2
- package/docs/reference/interfaces/IFileBlobStorageConnectorConstructorOptions.md +8 -0
- package/locales/en.json +0 -1
- package/package.json +7 -8
- package/dist/cjs/index.cjs +0 -183
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { mkdir, writeFile, readFile, unlink, access } from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { Guards, ComponentFactory, BaseError, Converter, Urn, GeneralError } from '@twin.org/core';
|
|
4
|
-
import { Sha256 } from '@twin.org/crypto';
|
|
5
|
-
|
|
6
1
|
// Copyright 2024 IOTA Stiftung.
|
|
7
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { access, mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { ContextIdHelper, ContextIdStore } from "@twin.org/context";
|
|
6
|
+
import { BaseError, ComponentFactory, Converter, GeneralError, Guards, Is, Urn } from "@twin.org/core";
|
|
7
|
+
import { Sha256 } from "@twin.org/crypto";
|
|
8
8
|
/**
|
|
9
9
|
* Class for performing blob storage operations in file.
|
|
10
10
|
*/
|
|
11
|
-
class FileBlobStorageConnector {
|
|
11
|
+
export class FileBlobStorageConnector {
|
|
12
12
|
/**
|
|
13
13
|
* The namespace for the items.
|
|
14
14
|
*/
|
|
@@ -27,6 +27,11 @@ class FileBlobStorageConnector {
|
|
|
27
27
|
* @internal
|
|
28
28
|
*/
|
|
29
29
|
_extension;
|
|
30
|
+
/**
|
|
31
|
+
* The keys to use from the context ids to create partitions.
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
_partitionContextIds;
|
|
30
35
|
/**
|
|
31
36
|
* Create a new instance of FileBlobStorageConnector.
|
|
32
37
|
* @param options The options for the connector.
|
|
@@ -37,6 +42,14 @@ class FileBlobStorageConnector {
|
|
|
37
42
|
Guards.stringValue(FileBlobStorageConnector.CLASS_NAME, "options.config.directory", options.config.directory);
|
|
38
43
|
this._directory = path.resolve(options.config.directory);
|
|
39
44
|
this._extension = options.config.extension ?? ".blob";
|
|
45
|
+
this._partitionContextIds = options.partitionContextIds;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns the class name of the component.
|
|
49
|
+
* @returns The class name of the component.
|
|
50
|
+
*/
|
|
51
|
+
className() {
|
|
52
|
+
return FileBlobStorageConnector.CLASS_NAME;
|
|
40
53
|
}
|
|
41
54
|
/**
|
|
42
55
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
@@ -46,24 +59,16 @@ class FileBlobStorageConnector {
|
|
|
46
59
|
async bootstrap(nodeLoggingComponentType) {
|
|
47
60
|
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
48
61
|
if (!(await this.dirExists(this._directory))) {
|
|
49
|
-
await nodeLogging?.log({
|
|
50
|
-
level: "info",
|
|
51
|
-
source: FileBlobStorageConnector.CLASS_NAME,
|
|
52
|
-
message: "directoryCreating",
|
|
53
|
-
data: {
|
|
54
|
-
directory: this._directory
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
62
|
try {
|
|
58
|
-
await mkdir(this._directory, { recursive: true });
|
|
59
63
|
await nodeLogging?.log({
|
|
60
64
|
level: "info",
|
|
61
65
|
source: FileBlobStorageConnector.CLASS_NAME,
|
|
62
|
-
message: "
|
|
66
|
+
message: "directoryCreating",
|
|
63
67
|
data: {
|
|
64
68
|
directory: this._directory
|
|
65
69
|
}
|
|
66
70
|
});
|
|
71
|
+
await mkdir(this._directory, { recursive: true });
|
|
67
72
|
}
|
|
68
73
|
catch (err) {
|
|
69
74
|
await nodeLogging?.log({
|
|
@@ -97,12 +102,15 @@ class FileBlobStorageConnector {
|
|
|
97
102
|
*/
|
|
98
103
|
async set(blob) {
|
|
99
104
|
Guards.uint8Array(FileBlobStorageConnector.CLASS_NAME, "blob", blob);
|
|
105
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
106
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
100
107
|
try {
|
|
101
|
-
if (!(await this.dirExists(this._directory))) {
|
|
102
|
-
await mkdir(this._directory);
|
|
103
|
-
}
|
|
104
108
|
const id = Converter.bytesToHex(Sha256.sum256(blob));
|
|
105
|
-
const fullPath =
|
|
109
|
+
const fullPath = this.createFullPath(id, partitionKey);
|
|
110
|
+
const dir = path.dirname(fullPath);
|
|
111
|
+
if (!(await this.dirExists(dir))) {
|
|
112
|
+
await mkdir(dir, { recursive: true });
|
|
113
|
+
}
|
|
106
114
|
await writeFile(fullPath, blob);
|
|
107
115
|
return `blob:${new Urn(FileBlobStorageConnector.NAMESPACE, id).toString()}`;
|
|
108
116
|
}
|
|
@@ -118,6 +126,8 @@ class FileBlobStorageConnector {
|
|
|
118
126
|
async get(id) {
|
|
119
127
|
Urn.guard(FileBlobStorageConnector.CLASS_NAME, "id", id);
|
|
120
128
|
const urnParsed = Urn.fromValidString(id);
|
|
129
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
130
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
121
131
|
if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
|
|
122
132
|
throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
123
133
|
namespace: FileBlobStorageConnector.NAMESPACE,
|
|
@@ -125,7 +135,7 @@ class FileBlobStorageConnector {
|
|
|
125
135
|
});
|
|
126
136
|
}
|
|
127
137
|
try {
|
|
128
|
-
const fullPath =
|
|
138
|
+
const fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);
|
|
129
139
|
return await readFile(fullPath);
|
|
130
140
|
}
|
|
131
141
|
catch (err) {
|
|
@@ -143,6 +153,8 @@ class FileBlobStorageConnector {
|
|
|
143
153
|
async remove(id) {
|
|
144
154
|
Urn.guard(FileBlobStorageConnector.CLASS_NAME, "id", id);
|
|
145
155
|
const urnParsed = Urn.fromValidString(id);
|
|
156
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
157
|
+
const partitionKey = ContextIdHelper.combinedContextKey(contextIds, this._partitionContextIds);
|
|
146
158
|
if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
|
|
147
159
|
throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
148
160
|
namespace: FileBlobStorageConnector.NAMESPACE,
|
|
@@ -150,7 +162,7 @@ class FileBlobStorageConnector {
|
|
|
150
162
|
});
|
|
151
163
|
}
|
|
152
164
|
try {
|
|
153
|
-
const fullPath =
|
|
165
|
+
const fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);
|
|
154
166
|
await unlink(fullPath);
|
|
155
167
|
return true;
|
|
156
168
|
}
|
|
@@ -176,6 +188,16 @@ class FileBlobStorageConnector {
|
|
|
176
188
|
return false;
|
|
177
189
|
}
|
|
178
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Create the full path for the blob.
|
|
193
|
+
* @param id The id of the blob.
|
|
194
|
+
* @param partitionKey The partition key.
|
|
195
|
+
* @returns The full path for the blob.
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
createFullPath(id, partitionKey) {
|
|
199
|
+
const partitionPath = Is.stringValue(partitionKey) ? path.join(partitionKey, id) : id;
|
|
200
|
+
return path.join(this._directory, `${partitionPath}${this._extension}`);
|
|
201
|
+
}
|
|
179
202
|
}
|
|
180
|
-
|
|
181
|
-
export { FileBlobStorageConnector };
|
|
203
|
+
//# sourceMappingURL=fileBlobStorageConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileBlobStorageConnector.js","sourceRoot":"","sources":["../../src/fileBlobStorageConnector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { access, mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\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 { IFileBlobStorageConnectorConstructorOptions } from \"./models/IFileBlobStorageConnectorConstructorOptions.js\";\n\n/**\n * Class for performing blob storage operations in file.\n */\nexport class FileBlobStorageConnector implements IBlobStorageConnector {\n\t/**\n\t * The namespace for the items.\n\t */\n\tpublic static readonly NAMESPACE: string = \"file\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<FileBlobStorageConnector>();\n\n\t/**\n\t * The directory to use for storage.\n\t * @internal\n\t */\n\tprivate readonly _directory: string;\n\n\t/**\n\t * The extension to use for storage.\n\t * @internal\n\t */\n\tprivate readonly _extension: string;\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 * Create a new instance of FileBlobStorageConnector.\n\t * @param options The options for the connector.\n\t */\n\tconstructor(options: IFileBlobStorageConnectorConstructorOptions) {\n\t\tGuards.object(FileBlobStorageConnector.CLASS_NAME, nameof(options), options);\n\t\tGuards.object(FileBlobStorageConnector.CLASS_NAME, nameof(options.config), options.config);\n\t\tGuards.stringValue(\n\t\t\tFileBlobStorageConnector.CLASS_NAME,\n\t\t\tnameof(options.config.directory),\n\t\t\toptions.config.directory\n\t\t);\n\t\tthis._directory = path.resolve(options.config.directory);\n\t\tthis._extension = options.config.extension ?? \".blob\";\n\t\tthis._partitionContextIds = options.partitionContextIds;\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 FileBlobStorageConnector.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\tif (!(await this.dirExists(this._directory))) {\n\t\t\ttry {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\tsource: FileBlobStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreating\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait mkdir(this._directory, { recursive: true });\n\t\t\t} catch (err) {\n\t\t\t\tawait nodeLogging?.log({\n\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\tsource: FileBlobStorageConnector.CLASS_NAME,\n\t\t\t\t\tmessage: \"directoryCreateFailed\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tdirectory: this._directory\n\t\t\t\t\t},\n\t\t\t\t\terror: BaseError.fromError(err)\n\t\t\t\t});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\tawait nodeLogging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: FileBlobStorageConnector.CLASS_NAME,\n\t\t\t\tmessage: \"directoryExists\",\n\t\t\t\tdata: {\n\t\t\t\t\tdirectory: this._directory\n\t\t\t\t}\n\t\t\t});\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(FileBlobStorageConnector.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\n\t\t\tconst fullPath = this.createFullPath(id, partitionKey);\n\n\t\t\tconst dir = path.dirname(fullPath);\n\t\t\tif (!(await this.dirExists(dir))) {\n\t\t\t\tawait mkdir(dir, { recursive: true });\n\t\t\t}\n\n\t\t\tawait writeFile(fullPath, blob);\n\n\t\t\treturn `blob:${new Urn(FileBlobStorageConnector.NAMESPACE, id).toString()}`;\n\t\t} catch (err) {\n\t\t\tthrow new GeneralError(FileBlobStorageConnector.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(FileBlobStorageConnector.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() !== FileBlobStorageConnector.NAMESPACE) {\n\t\t\tthrow new GeneralError(FileBlobStorageConnector.CLASS_NAME, \"namespaceMismatch\", {\n\t\t\t\tnamespace: FileBlobStorageConnector.NAMESPACE,\n\t\t\t\tid\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tconst fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);\n\n\t\t\treturn await readFile(fullPath);\n\t\t} catch (err) {\n\t\t\tif (BaseError.isErrorCode(err, \"ENOENT\")) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new GeneralError(FileBlobStorageConnector.CLASS_NAME, \"getBlobFailed\", { id }, err);\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(FileBlobStorageConnector.CLASS_NAME, nameof(id), id);\n\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() !== FileBlobStorageConnector.NAMESPACE) {\n\t\t\tthrow new GeneralError(FileBlobStorageConnector.CLASS_NAME, \"namespaceMismatch\", {\n\t\t\t\tnamespace: FileBlobStorageConnector.NAMESPACE,\n\t\t\t\tid\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\tconst fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);\n\n\t\t\tawait unlink(fullPath);\n\n\t\t\treturn true;\n\t\t} catch (err) {\n\t\t\tif (BaseError.isErrorCode(err, \"ENOENT\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrow new GeneralError(FileBlobStorageConnector.CLASS_NAME, \"removeBlobFailed\", { id }, err);\n\t\t}\n\t}\n\n\t/**\n\t * Check if the dir exists.\n\t * @param dir The directory to check.\n\t * @returns True if the dir exists.\n\t * @internal\n\t */\n\tprivate async dirExists(dir: string): Promise<boolean> {\n\t\ttry {\n\t\t\tawait access(dir);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Create the full path for the blob.\n\t * @param id The id of the blob.\n\t * @param partitionKey The partition key.\n\t * @returns The full path for the blob.\n\t * @internal\n\t */\n\tprivate createFullPath(id: string, partitionKey?: string): string {\n\t\tconst partitionPath = Is.stringValue(partitionKey) ? path.join(partitionKey, id) : id;\n\t\treturn path.join(this._directory, `${partitionPath}${this._extension}`);\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 "./fileBlobStorageConnector.js";
|
|
4
|
+
export * from "./models/IFileBlobStorageConnectorConfig.js";
|
|
5
|
+
export * from "./models/IFileBlobStorageConnectorConstructorOptions.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,+BAA+B,CAAC;AAC9C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,yDAAyD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./fileBlobStorageConnector.js\";\nexport * from \"./models/IFileBlobStorageConnectorConfig.js\";\nexport * from \"./models/IFileBlobStorageConnectorConstructorOptions.js\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IFileBlobStorageConnectorConfig.js","sourceRoot":"","sources":["../../../src/models/IFileBlobStorageConnectorConfig.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 File Blob Storage Connector.\n */\nexport interface IFileBlobStorageConnectorConfig {\n\t/**\n\t * The directory to use for storage.\n\t */\n\tdirectory: string;\n\n\t/**\n\t * The extension to add to files when they are stored.\n\t */\n\textension?: string;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IFileBlobStorageConnectorConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IFileBlobStorageConnectorConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IFileBlobStorageConnectorConfig } from \"./IFileBlobStorageConnectorConfig.js\";\n\n/**\n * Options for the File Blob Storage Connector constructor.\n */\nexport interface IFileBlobStorageConnectorConstructorOptions {\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: IFileBlobStorageConnectorConfig;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IBlobStorageConnector } from "@twin.org/blob-storage-models";
|
|
2
|
-
import type { IFileBlobStorageConnectorConstructorOptions } from "./models/IFileBlobStorageConnectorConstructorOptions";
|
|
2
|
+
import type { IFileBlobStorageConnectorConstructorOptions } from "./models/IFileBlobStorageConnectorConstructorOptions.js";
|
|
3
3
|
/**
|
|
4
4
|
* Class for performing blob storage operations in file.
|
|
5
5
|
*/
|
|
@@ -17,6 +17,11 @@ export declare class FileBlobStorageConnector implements IBlobStorageConnector {
|
|
|
17
17
|
* @param options The options for the connector.
|
|
18
18
|
*/
|
|
19
19
|
constructor(options: IFileBlobStorageConnectorConstructorOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Returns the class name of the component.
|
|
22
|
+
* @returns The class name of the component.
|
|
23
|
+
*/
|
|
24
|
+
className(): string;
|
|
20
25
|
/**
|
|
21
26
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
22
27
|
* @param nodeLoggingComponentType The node logging component type.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from "./fileBlobStorageConnector";
|
|
2
|
-
export * from "./models/IFileBlobStorageConnectorConfig";
|
|
3
|
-
export * from "./models/IFileBlobStorageConnectorConstructorOptions";
|
|
1
|
+
export * from "./fileBlobStorageConnector.js";
|
|
2
|
+
export * from "./models/IFileBlobStorageConnectorConfig.js";
|
|
3
|
+
export * from "./models/IFileBlobStorageConnectorConstructorOptions.js";
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import type { IFileBlobStorageConnectorConfig } from "./IFileBlobStorageConnectorConfig";
|
|
1
|
+
import type { IFileBlobStorageConnectorConfig } from "./IFileBlobStorageConnectorConfig.js";
|
|
2
2
|
/**
|
|
3
3
|
* Options for the File Blob Storage Connector constructor.
|
|
4
4
|
*/
|
|
5
5
|
export interface IFileBlobStorageConnectorConstructorOptions {
|
|
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,24 @@
|
|
|
1
1
|
# @twin.org/blob-storage-connector-file - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.1](https://github.com/twinfoundation/blob-storage/compare/blob-storage-connector-file-v0.0.3-next.0...blob-storage-connector-file-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
|
+
|
|
3
22
|
## [0.0.2-next.5](https://github.com/twinfoundation/blob-storage/compare/blob-storage-connector-file-v0.0.2-next.4...blob-storage-connector-file-v0.0.2-next.5) (2025-10-09)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -44,6 +44,24 @@ Runtime name for the class.
|
|
|
44
44
|
|
|
45
45
|
## Methods
|
|
46
46
|
|
|
47
|
+
### className()
|
|
48
|
+
|
|
49
|
+
> **className**(): `string`
|
|
50
|
+
|
|
51
|
+
Returns the class name of the component.
|
|
52
|
+
|
|
53
|
+
#### Returns
|
|
54
|
+
|
|
55
|
+
`string`
|
|
56
|
+
|
|
57
|
+
The class name of the component.
|
|
58
|
+
|
|
59
|
+
#### Implementation of
|
|
60
|
+
|
|
61
|
+
`IBlobStorageConnector.className`
|
|
62
|
+
|
|
63
|
+
***
|
|
64
|
+
|
|
47
65
|
### bootstrap()
|
|
48
66
|
|
|
49
67
|
> **bootstrap**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
|
|
@@ -98,7 +116,7 @@ The id of the stored blob in urn format.
|
|
|
98
116
|
|
|
99
117
|
### get()
|
|
100
118
|
|
|
101
|
-
> **get**(`id`): `Promise`\<`
|
|
119
|
+
> **get**(`id`): `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
102
120
|
|
|
103
121
|
Get the blob.
|
|
104
122
|
|
|
@@ -112,7 +130,7 @@ The id of the blob to get in urn format.
|
|
|
112
130
|
|
|
113
131
|
#### Returns
|
|
114
132
|
|
|
115
|
-
`Promise`\<`
|
|
133
|
+
`Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
|
|
116
134
|
|
|
117
135
|
The data for the blob if it can be found or undefined.
|
|
118
136
|
|
|
@@ -4,6 +4,14 @@ Options for the File 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**: [`IFileBlobStorageConnectorConfig`](IFileBlobStorageConnectorConfig.md)
|
package/locales/en.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/blob-storage-connector-file",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-next.1",
|
|
4
4
|
"description": "Blob Storage connector implementation using file storage",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,26 +14,25 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@twin.org/blob-storage-models": "0.0.
|
|
17
|
+
"@twin.org/blob-storage-models": "0.0.3-next.1",
|
|
18
|
+
"@twin.org/context": "next",
|
|
18
19
|
"@twin.org/core": "next",
|
|
19
20
|
"@twin.org/crypto": "next",
|
|
20
21
|
"@twin.org/logging-models": "next",
|
|
21
22
|
"@twin.org/nameof": "next"
|
|
22
23
|
},
|
|
23
|
-
"main": "./dist/
|
|
24
|
-
"module": "./dist/esm/index.mjs",
|
|
24
|
+
"main": "./dist/es/index.js",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
28
28
|
"types": "./dist/types/index.d.ts",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
29
|
+
"import": "./dist/es/index.js",
|
|
30
|
+
"default": "./dist/es/index.js"
|
|
31
31
|
},
|
|
32
32
|
"./locales/*.json": "./locales/*.json"
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
|
-
"dist/
|
|
36
|
-
"dist/esm",
|
|
35
|
+
"dist/es",
|
|
37
36
|
"dist/types",
|
|
38
37
|
"locales",
|
|
39
38
|
"docs"
|
package/dist/cjs/index.cjs
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var promises = require('node:fs/promises');
|
|
4
|
-
var path = require('node:path');
|
|
5
|
-
var core = require('@twin.org/core');
|
|
6
|
-
var crypto = require('@twin.org/crypto');
|
|
7
|
-
|
|
8
|
-
// Copyright 2024 IOTA Stiftung.
|
|
9
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
10
|
-
/**
|
|
11
|
-
* Class for performing blob storage operations in file.
|
|
12
|
-
*/
|
|
13
|
-
class FileBlobStorageConnector {
|
|
14
|
-
/**
|
|
15
|
-
* The namespace for the items.
|
|
16
|
-
*/
|
|
17
|
-
static NAMESPACE = "file";
|
|
18
|
-
/**
|
|
19
|
-
* Runtime name for the class.
|
|
20
|
-
*/
|
|
21
|
-
static CLASS_NAME = "FileBlobStorageConnector";
|
|
22
|
-
/**
|
|
23
|
-
* The directory to use for storage.
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
_directory;
|
|
27
|
-
/**
|
|
28
|
-
* The extension to use for storage.
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
_extension;
|
|
32
|
-
/**
|
|
33
|
-
* Create a new instance of FileBlobStorageConnector.
|
|
34
|
-
* @param options The options for the connector.
|
|
35
|
-
*/
|
|
36
|
-
constructor(options) {
|
|
37
|
-
core.Guards.object(FileBlobStorageConnector.CLASS_NAME, "options", options);
|
|
38
|
-
core.Guards.object(FileBlobStorageConnector.CLASS_NAME, "options.config", options.config);
|
|
39
|
-
core.Guards.stringValue(FileBlobStorageConnector.CLASS_NAME, "options.config.directory", options.config.directory);
|
|
40
|
-
this._directory = path.resolve(options.config.directory);
|
|
41
|
-
this._extension = options.config.extension ?? ".blob";
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Bootstrap the component by creating and initializing any resources it needs.
|
|
45
|
-
* @param nodeLoggingComponentType The node logging component type.
|
|
46
|
-
* @returns True if the bootstrapping process was successful.
|
|
47
|
-
*/
|
|
48
|
-
async bootstrap(nodeLoggingComponentType) {
|
|
49
|
-
const nodeLogging = core.ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
50
|
-
if (!(await this.dirExists(this._directory))) {
|
|
51
|
-
await nodeLogging?.log({
|
|
52
|
-
level: "info",
|
|
53
|
-
source: FileBlobStorageConnector.CLASS_NAME,
|
|
54
|
-
message: "directoryCreating",
|
|
55
|
-
data: {
|
|
56
|
-
directory: this._directory
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
try {
|
|
60
|
-
await promises.mkdir(this._directory, { recursive: true });
|
|
61
|
-
await nodeLogging?.log({
|
|
62
|
-
level: "info",
|
|
63
|
-
source: FileBlobStorageConnector.CLASS_NAME,
|
|
64
|
-
message: "directoryCreated",
|
|
65
|
-
data: {
|
|
66
|
-
directory: this._directory
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
await nodeLogging?.log({
|
|
72
|
-
level: "error",
|
|
73
|
-
source: FileBlobStorageConnector.CLASS_NAME,
|
|
74
|
-
message: "directoryCreateFailed",
|
|
75
|
-
data: {
|
|
76
|
-
directory: this._directory
|
|
77
|
-
},
|
|
78
|
-
error: core.BaseError.fromError(err)
|
|
79
|
-
});
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
await nodeLogging?.log({
|
|
85
|
-
level: "info",
|
|
86
|
-
source: FileBlobStorageConnector.CLASS_NAME,
|
|
87
|
-
message: "directoryExists",
|
|
88
|
-
data: {
|
|
89
|
-
directory: this._directory
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Set the blob.
|
|
97
|
-
* @param blob The data for the blob.
|
|
98
|
-
* @returns The id of the stored blob in urn format.
|
|
99
|
-
*/
|
|
100
|
-
async set(blob) {
|
|
101
|
-
core.Guards.uint8Array(FileBlobStorageConnector.CLASS_NAME, "blob", blob);
|
|
102
|
-
try {
|
|
103
|
-
if (!(await this.dirExists(this._directory))) {
|
|
104
|
-
await promises.mkdir(this._directory);
|
|
105
|
-
}
|
|
106
|
-
const id = core.Converter.bytesToHex(crypto.Sha256.sum256(blob));
|
|
107
|
-
const fullPath = path.join(this._directory, `${id}${this._extension}`);
|
|
108
|
-
await promises.writeFile(fullPath, blob);
|
|
109
|
-
return `blob:${new core.Urn(FileBlobStorageConnector.NAMESPACE, id).toString()}`;
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
throw new core.GeneralError(FileBlobStorageConnector.CLASS_NAME, "setBlobFailed", undefined, err);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Get the blob.
|
|
117
|
-
* @param id The id of the blob to get in urn format.
|
|
118
|
-
* @returns The data for the blob if it can be found or undefined.
|
|
119
|
-
*/
|
|
120
|
-
async get(id) {
|
|
121
|
-
core.Urn.guard(FileBlobStorageConnector.CLASS_NAME, "id", id);
|
|
122
|
-
const urnParsed = core.Urn.fromValidString(id);
|
|
123
|
-
if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
|
|
124
|
-
throw new core.GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
125
|
-
namespace: FileBlobStorageConnector.NAMESPACE,
|
|
126
|
-
id
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
try {
|
|
130
|
-
const fullPath = path.join(this._directory, `${urnParsed.namespaceSpecific(1)}${this._extension}`);
|
|
131
|
-
return await promises.readFile(fullPath);
|
|
132
|
-
}
|
|
133
|
-
catch (err) {
|
|
134
|
-
if (core.BaseError.isErrorCode(err, "ENOENT")) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
throw new core.GeneralError(FileBlobStorageConnector.CLASS_NAME, "getBlobFailed", { id }, err);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Remove the blob.
|
|
142
|
-
* @param id The id of the blob to remove in urn format.
|
|
143
|
-
* @returns True if the blob was found.
|
|
144
|
-
*/
|
|
145
|
-
async remove(id) {
|
|
146
|
-
core.Urn.guard(FileBlobStorageConnector.CLASS_NAME, "id", id);
|
|
147
|
-
const urnParsed = core.Urn.fromValidString(id);
|
|
148
|
-
if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
|
|
149
|
-
throw new core.GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
|
|
150
|
-
namespace: FileBlobStorageConnector.NAMESPACE,
|
|
151
|
-
id
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
try {
|
|
155
|
-
const fullPath = path.join(this._directory, `${urnParsed.namespaceSpecific(1)}${this._extension}`);
|
|
156
|
-
await promises.unlink(fullPath);
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
if (core.BaseError.isErrorCode(err, "ENOENT")) {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
throw new core.GeneralError(FileBlobStorageConnector.CLASS_NAME, "removeBlobFailed", { id }, err);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Check if the dir exists.
|
|
168
|
-
* @param dir The directory to check.
|
|
169
|
-
* @returns True if the dir exists.
|
|
170
|
-
* @internal
|
|
171
|
-
*/
|
|
172
|
-
async dirExists(dir) {
|
|
173
|
-
try {
|
|
174
|
-
await promises.access(dir);
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
catch {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
exports.FileBlobStorageConnector = FileBlobStorageConnector;
|