@twin.org/blob-storage-connector-file 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.
@@ -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
  */
@@ -16,7 +16,7 @@ class FileBlobStorageConnector {
16
16
  /**
17
17
  * Runtime name for the class.
18
18
  */
19
- CLASS_NAME = "FileBlobStorageConnector";
19
+ static CLASS_NAME = "FileBlobStorageConnector";
20
20
  /**
21
21
  * The directory to use for storage.
22
22
  * @internal
@@ -27,16 +27,29 @@ 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.
33
38
  */
34
39
  constructor(options) {
35
- Guards.object(this.CLASS_NAME, "options", options);
36
- Guards.object(this.CLASS_NAME, "options.config", options.config);
37
- Guards.stringValue(this.CLASS_NAME, "options.config.directory", options.config.directory);
40
+ Guards.object(FileBlobStorageConnector.CLASS_NAME, "options", options);
41
+ Guards.object(FileBlobStorageConnector.CLASS_NAME, "options.config", options.config);
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,29 +59,21 @@ 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: this.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
- source: this.CLASS_NAME,
62
- message: "directoryCreated",
65
+ source: FileBlobStorageConnector.CLASS_NAME,
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({
70
75
  level: "error",
71
- source: this.CLASS_NAME,
76
+ source: FileBlobStorageConnector.CLASS_NAME,
72
77
  message: "directoryCreateFailed",
73
78
  data: {
74
79
  directory: this._directory
@@ -81,7 +86,7 @@ class FileBlobStorageConnector {
81
86
  else {
82
87
  await nodeLogging?.log({
83
88
  level: "info",
84
- source: this.CLASS_NAME,
89
+ source: FileBlobStorageConnector.CLASS_NAME,
85
90
  message: "directoryExists",
86
91
  data: {
87
92
  directory: this._directory
@@ -96,18 +101,21 @@ class FileBlobStorageConnector {
96
101
  * @returns The id of the stored blob in urn format.
97
102
  */
98
103
  async set(blob) {
99
- Guards.uint8Array(this.CLASS_NAME, "blob", blob);
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 = path.join(this._directory, `${id}${this._extension}`);
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
  }
109
117
  catch (err) {
110
- throw new GeneralError(this.CLASS_NAME, "setBlobFailed", undefined, err);
118
+ throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "setBlobFailed", undefined, err);
111
119
  }
112
120
  }
113
121
  /**
@@ -116,23 +124,25 @@ class FileBlobStorageConnector {
116
124
  * @returns The data for the blob if it can be found or undefined.
117
125
  */
118
126
  async get(id) {
119
- Urn.guard(this.CLASS_NAME, "id", id);
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
- throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
132
+ throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
123
133
  namespace: FileBlobStorageConnector.NAMESPACE,
124
134
  id
125
135
  });
126
136
  }
127
137
  try {
128
- const fullPath = path.join(this._directory, `${urnParsed.namespaceSpecific(1)}${this._extension}`);
138
+ const fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);
129
139
  return await readFile(fullPath);
130
140
  }
131
141
  catch (err) {
132
142
  if (BaseError.isErrorCode(err, "ENOENT")) {
133
143
  return;
134
144
  }
135
- throw new GeneralError(this.CLASS_NAME, "getBlobFailed", { id }, err);
145
+ throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "getBlobFailed", { id }, err);
136
146
  }
137
147
  }
138
148
  /**
@@ -141,16 +151,18 @@ class FileBlobStorageConnector {
141
151
  * @returns True if the blob was found.
142
152
  */
143
153
  async remove(id) {
144
- Urn.guard(this.CLASS_NAME, "id", id);
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
- throw new GeneralError(this.CLASS_NAME, "namespaceMismatch", {
159
+ throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "namespaceMismatch", {
148
160
  namespace: FileBlobStorageConnector.NAMESPACE,
149
161
  id
150
162
  });
151
163
  }
152
164
  try {
153
- const fullPath = path.join(this._directory, `${urnParsed.namespaceSpecific(1)}${this._extension}`);
165
+ const fullPath = this.createFullPath(urnParsed.namespaceSpecific(1), partitionKey);
154
166
  await unlink(fullPath);
155
167
  return true;
156
168
  }
@@ -158,7 +170,7 @@ class FileBlobStorageConnector {
158
170
  if (BaseError.isErrorCode(err, "ENOENT")) {
159
171
  return false;
160
172
  }
161
- throw new GeneralError(this.CLASS_NAME, "removeBlobFailed", { id }, err);
173
+ throw new GeneralError(FileBlobStorageConnector.CLASS_NAME, "removeBlobFailed", { id }, err);
162
174
  }
163
175
  }
164
176
  /**
@@ -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":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EACN,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,MAAM,EACN,EAAE,EACF,GAAG,EACH,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK1C;;GAEG;AACH,MAAM,OAAO,wBAAwB;IACpC;;OAEG;IACI,MAAM,CAAU,SAAS,GAAW,MAAM,CAAC;IAElD;;OAEG;IACI,MAAM,CAAU,UAAU,8BAA8C;IAE/E;;;OAGG;IACc,UAAU,CAAS;IAEpC;;;OAGG;IACc,UAAU,CAAS;IAEpC;;;OAGG;IACc,oBAAoB,CAAY;IAEjD;;;OAGG;IACH,YAAY,OAAoD;QAC/D,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,UAAU,aAAmB,OAAO,CAAC,CAAC;QAC7E,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,UAAU,oBAA0B,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3F,MAAM,CAAC,WAAW,CACjB,wBAAwB,CAAC,UAAU,8BAEnC,OAAO,CAAC,MAAM,CAAC,SAAS,CACxB,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC;QACtD,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IACzD,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,wBAAwB,CAAC,UAAU,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAC,wBAAiC;QACvD,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAoB,wBAAwB,CAAC,CAAC;QAE9F,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC;gBACJ,MAAM,WAAW,EAAE,GAAG,CAAC;oBACtB,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,wBAAwB,CAAC,UAAU;oBAC3C,OAAO,EAAE,mBAAmB;oBAC5B,IAAI,EAAE;wBACL,SAAS,EAAE,IAAI,CAAC,UAAU;qBAC1B;iBACD,CAAC,CAAC;gBACH,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,MAAM,WAAW,EAAE,GAAG,CAAC;oBACtB,KAAK,EAAE,OAAO;oBACd,MAAM,EAAE,wBAAwB,CAAC,UAAU;oBAC3C,OAAO,EAAE,uBAAuB;oBAChC,IAAI,EAAE;wBACL,SAAS,EAAE,IAAI,CAAC,UAAU;qBAC1B;oBACD,KAAK,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC;iBAC/B,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC;YACd,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,WAAW,EAAE,GAAG,CAAC;gBACtB,KAAK,EAAE,MAAM;gBACb,MAAM,EAAE,wBAAwB,CAAC,UAAU;gBAC3C,OAAO,EAAE,iBAAiB;gBAC1B,IAAI,EAAE;oBACL,SAAS,EAAE,IAAI,CAAC,UAAU;iBAC1B;aACD,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,GAAG,CAAC,IAAgB;QAChC,MAAM,CAAC,UAAU,CAAC,wBAAwB,CAAC,UAAU,UAAgB,IAAI,CAAC,CAAC;QAE3E,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,CAAC;YACJ,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAErD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;YAEvD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAClC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC;YAED,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAEhC,OAAO,QAAQ,IAAI,GAAG,CAAC,wBAAwB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC7E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9F,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,GAAG,CAAC,EAAU;QAC1B,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAC/D,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAE1C,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,SAAS,CAAC,eAAe,EAAE,KAAK,wBAAwB,CAAC,SAAS,EAAE,CAAC;YACxE,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,EAAE;gBAChF,SAAS,EAAE,wBAAwB,CAAC,SAAS;gBAC7C,EAAE;aACF,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YAEnF,OAAO,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC1C,OAAO;YACR,CAAC;YACD,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,UAAU,EAAE,eAAe,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3F,CAAC;IACF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,MAAM,CAAC,EAAU;QAC7B,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,UAAU,QAAc,EAAE,CAAC,CAAC;QAE/D,MAAM,SAAS,GAAG,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAE1C,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,YAAY,GAAG,eAAe,CAAC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE/F,IAAI,SAAS,CAAC,eAAe,EAAE,KAAK,wBAAwB,CAAC,SAAS,EAAE,CAAC;YACxE,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,EAAE;gBAChF,SAAS,EAAE,wBAAwB,CAAC,SAAS;gBAC7C,EAAE;aACF,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YAEnF,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;YAEvB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACd,CAAC;YACD,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,UAAU,EAAE,kBAAkB,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9F,CAAC;IACF,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,SAAS,CAAC,GAAW;QAClC,IAAI,CAAC;YACJ,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAClB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACK,cAAc,CAAC,EAAU,EAAE,YAAqB;QACvD,MAAM,aAAa,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACzE,CAAC","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"]}
@@ -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,4 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ export {};
4
+ //# sourceMappingURL=IFileBlobStorageConnectorConfig.js.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IFileBlobStorageConnectorConstructorOptions.js.map
@@ -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
  */
@@ -11,12 +11,17 @@ export declare class FileBlobStorageConnector implements IBlobStorageConnector {
11
11
  /**
12
12
  * Runtime name for the class.
13
13
  */
14
- readonly CLASS_NAME: string;
14
+ static readonly CLASS_NAME: string;
15
15
  /**
16
16
  * Create a new instance of FileBlobStorageConnector.
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.
@@ -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,38 @@
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
+
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)
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-file-v0.0.2-next.3...blob-storage-connector-file-v0.0.2-next.4) (2025-10-02)
4
37
 
5
38
 
@@ -38,15 +38,29 @@ The namespace for the items.
38
38
 
39
39
  ### CLASS\_NAME
40
40
 
41
- > `readonly` **CLASS\_NAME**: `string`
41
+ > `readonly` `static` **CLASS\_NAME**: `string`
42
42
 
43
43
  Runtime name for the class.
44
44
 
45
+ ## Methods
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
+
45
59
  #### Implementation of
46
60
 
47
- `IBlobStorageConnector.CLASS_NAME`
61
+ `IBlobStorageConnector.className`
48
62
 
49
- ## Methods
63
+ ***
50
64
 
51
65
  ### bootstrap()
52
66
 
@@ -102,7 +116,7 @@ The id of the stored blob in urn format.
102
116
 
103
117
  ### get()
104
118
 
105
- > **get**(`id`): `Promise`\<`undefined` \| `Uint8Array`\<`ArrayBufferLike`\>\>
119
+ > **get**(`id`): `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
106
120
 
107
121
  Get the blob.
108
122
 
@@ -116,7 +130,7 @@ The id of the blob to get in urn format.
116
130
 
117
131
  #### Returns
118
132
 
119
- `Promise`\<`undefined` \| `Uint8Array`\<`ArrayBufferLike`\>\>
133
+ `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `undefined`\>
120
134
 
121
135
  The data for the blob if it can be found or undefined.
122
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
@@ -2,7 +2,6 @@
2
2
  "info": {
3
3
  "fileBlobStorageConnector": {
4
4
  "directoryCreating": "Creating directory \"{directory}\"",
5
- "directoryCreated": "Created directory \"{directory}\"",
6
5
  "directoryExists": "Skipping create directory \"{directory}\" as it already exists"
7
6
  }
8
7
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/blob-storage-connector-file",
3
- "version": "0.0.2-next.4",
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.2-next.4",
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/cjs/index.cjs",
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
- "require": "./dist/cjs/index.cjs",
30
- "import": "./dist/esm/index.mjs"
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/cjs",
36
- "dist/esm",
35
+ "dist/es",
37
36
  "dist/types",
38
37
  "locales",
39
38
  "docs"
@@ -52,5 +51,9 @@
52
51
  "connector",
53
52
  "adapter",
54
53
  "integration"
55
- ]
54
+ ],
55
+ "bugs": {
56
+ "url": "git+https://github.com/twinfoundation/blob-storage/issues"
57
+ },
58
+ "homepage": "https://twindev.org"
56
59
  }
@@ -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
- 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(this.CLASS_NAME, "options", options);
38
- core.Guards.object(this.CLASS_NAME, "options.config", options.config);
39
- core.Guards.stringValue(this.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: this.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: this.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: this.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: this.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(this.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(this.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(this.CLASS_NAME, "id", id);
122
- const urnParsed = core.Urn.fromValidString(id);
123
- if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
124
- throw new core.GeneralError(this.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(this.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(this.CLASS_NAME, "id", id);
147
- const urnParsed = core.Urn.fromValidString(id);
148
- if (urnParsed.namespaceMethod() !== FileBlobStorageConnector.NAMESPACE) {
149
- throw new core.GeneralError(this.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(this.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;