@twin.org/blob-storage-service 0.0.2-next.5 → 0.0.3-next.2
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/es/blobStorageRoutes.js +528 -0
- package/dist/es/blobStorageRoutes.js.map +1 -0
- package/dist/es/blobStorageService.js +359 -0
- package/dist/es/blobStorageService.js.map +1 -0
- package/dist/es/entities/blobStorageEntry.js +96 -0
- package/dist/es/entities/blobStorageEntry.js.map +1 -0
- package/dist/es/index.js +10 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/IBlobStorageServiceConfig.js +4 -0
- package/dist/es/models/IBlobStorageServiceConfig.js.map +1 -0
- package/dist/es/models/IBlobStorageServiceConstructorOptions.js +2 -0
- package/dist/es/models/IBlobStorageServiceConstructorOptions.js.map +1 -0
- package/dist/es/restEntryPoints.js +15 -0
- package/dist/es/restEntryPoints.js.map +1 -0
- package/dist/es/schema.js +11 -0
- package/dist/es/schema.js.map +1 -0
- package/dist/types/blobStorageService.d.ts +12 -14
- package/dist/types/entities/blobStorageEntry.d.ts +0 -4
- package/dist/types/index.d.ts +7 -7
- package/dist/types/models/IBlobStorageServiceConfig.d.ts +0 -4
- package/dist/types/models/IBlobStorageServiceConstructorOptions.d.ts +1 -1
- package/docs/changelog.md +54 -0
- package/docs/open-api/spec.json +14 -23
- package/docs/reference/classes/BlobStorageEntry.md +0 -8
- package/docs/reference/classes/BlobStorageService.md +24 -48
- package/docs/reference/interfaces/IBlobStorageServiceConfig.md +0 -8
- package/package.json +7 -8
- package/dist/cjs/index.cjs +0 -1084
- package/dist/esm/index.mjs +0 -1072
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { BlobStorageConnectorFactory, BlobStorageContexts, BlobStorageTypes } from "@twin.org/blob-storage-models";
|
|
4
|
+
import { ContextIdHelper, ContextIdKeys, ContextIdStore } from "@twin.org/context";
|
|
5
|
+
import { Compression, Converter, GeneralError, Guards, Is, NotFoundError, Urn, Validation } from "@twin.org/core";
|
|
6
|
+
import { Sha256 } from "@twin.org/crypto";
|
|
7
|
+
import { JsonLdHelper, JsonLdProcessor } from "@twin.org/data-json-ld";
|
|
8
|
+
import { ComparisonOperator, EntitySchemaHelper, LogicalOperator, SortDirection } from "@twin.org/entity";
|
|
9
|
+
import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
|
|
10
|
+
import { SchemaOrgContexts, SchemaOrgDataTypes, SchemaOrgTypes } from "@twin.org/standards-schema-org";
|
|
11
|
+
import { VaultConnectorFactory, VaultEncryptionType } from "@twin.org/vault-models";
|
|
12
|
+
import { MimeTypeHelper } from "@twin.org/web";
|
|
13
|
+
/**
|
|
14
|
+
* Service for performing blob storage operations to a connector.
|
|
15
|
+
*/
|
|
16
|
+
export class BlobStorageService {
|
|
17
|
+
/**
|
|
18
|
+
* Runtime name for the class.
|
|
19
|
+
*/
|
|
20
|
+
static CLASS_NAME = "BlobStorageService";
|
|
21
|
+
/**
|
|
22
|
+
* The namespace supported by the blob storage service.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
static _NAMESPACE = "blob";
|
|
26
|
+
/**
|
|
27
|
+
* The namespace of the default storage connector to use.
|
|
28
|
+
* Defaults to the first entry in the factory if not provided.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
_defaultNamespace;
|
|
32
|
+
/**
|
|
33
|
+
* The storage connector for the metadata.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
_entryEntityStorage;
|
|
37
|
+
/**
|
|
38
|
+
* The vault connector for the encryption, can be undefined if no encryption required.
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
_vaultConnector;
|
|
42
|
+
/**
|
|
43
|
+
* The id of the vault key to use for encryption if the service has a vault connector configured.
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
_vaultKeyId;
|
|
47
|
+
/**
|
|
48
|
+
* Create a new instance of BlobStorageService.
|
|
49
|
+
* @param options The options for the service.
|
|
50
|
+
*/
|
|
51
|
+
constructor(options) {
|
|
52
|
+
const names = BlobStorageConnectorFactory.names();
|
|
53
|
+
if (names.length === 0) {
|
|
54
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "noConnectors");
|
|
55
|
+
}
|
|
56
|
+
this._entryEntityStorage = EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
|
|
57
|
+
if (Is.stringValue(options?.vaultConnectorType)) {
|
|
58
|
+
this._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType);
|
|
59
|
+
}
|
|
60
|
+
this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
|
|
61
|
+
this._vaultKeyId = options?.config?.vaultKeyId;
|
|
62
|
+
SchemaOrgDataTypes.registerRedirects();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the class name of the component.
|
|
66
|
+
* @returns The class name of the component.
|
|
67
|
+
*/
|
|
68
|
+
className() {
|
|
69
|
+
return BlobStorageService.CLASS_NAME;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create the blob with some metadata.
|
|
73
|
+
* @param blob The data for the blob in base64 format.
|
|
74
|
+
* @param encodingFormat Mime type for the blob, will be detected if left undefined.
|
|
75
|
+
* @param fileExtension Extension for the blob, will be detected if left undefined.
|
|
76
|
+
* @param metadata Data for the custom metadata as JSON-LD.
|
|
77
|
+
* @param options Optional options for the creation of the blob.
|
|
78
|
+
* @param options.disableEncryption Disables encryption if enabled by default.
|
|
79
|
+
* @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
|
|
80
|
+
* @param options.compress Optional compression type to use for the blob, defaults to no compression.
|
|
81
|
+
* @param options.namespace The namespace to use for storing, defaults to component configured namespace.
|
|
82
|
+
* @returns The id of the stored blob in urn format.
|
|
83
|
+
*/
|
|
84
|
+
async create(blob, encodingFormat, fileExtension, metadata, options) {
|
|
85
|
+
Guards.stringBase64(BlobStorageService.CLASS_NAME, "blob", blob);
|
|
86
|
+
const disableEncryption = options?.disableEncryption ?? false;
|
|
87
|
+
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
88
|
+
const encryptionEnabled = !disableEncryption && Is.stringValue(vaultKeyId);
|
|
89
|
+
try {
|
|
90
|
+
const connectorNamespace = options?.namespace ?? this._defaultNamespace;
|
|
91
|
+
const blobStorageConnector = BlobStorageConnectorFactory.get(connectorNamespace);
|
|
92
|
+
// Convert the base64 data into bytes
|
|
93
|
+
let storeBlob = Converter.base64ToBytes(blob);
|
|
94
|
+
const blobSize = storeBlob.length;
|
|
95
|
+
// See if we can detect the mime type and default extension for the data.
|
|
96
|
+
// If not already supplied by the caller. We have to perform this operation
|
|
97
|
+
// on the unencrypted data.
|
|
98
|
+
if (!Is.stringValue(encodingFormat)) {
|
|
99
|
+
encodingFormat = await MimeTypeHelper.detect(storeBlob);
|
|
100
|
+
}
|
|
101
|
+
if (!Is.stringValue(fileExtension) && Is.stringValue(encodingFormat)) {
|
|
102
|
+
fileExtension = MimeTypeHelper.defaultExtension(encodingFormat);
|
|
103
|
+
}
|
|
104
|
+
if (Is.object(metadata)) {
|
|
105
|
+
const validationFailures = [];
|
|
106
|
+
await JsonLdHelper.validate(metadata, validationFailures);
|
|
107
|
+
Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
108
|
+
}
|
|
109
|
+
const blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;
|
|
110
|
+
if (!Is.empty(options?.compress)) {
|
|
111
|
+
storeBlob = await Compression.compress(storeBlob, options.compress);
|
|
112
|
+
}
|
|
113
|
+
// If we have a vault connector then encrypt the data.
|
|
114
|
+
if (encryptionEnabled) {
|
|
115
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
116
|
+
ContextIdHelper.guard(contextIds, ContextIdKeys.Organization);
|
|
117
|
+
if (Is.empty(this._vaultConnector)) {
|
|
118
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
119
|
+
}
|
|
120
|
+
storeBlob = await this._vaultConnector.encrypt(`${contextIds[ContextIdKeys.Organization]}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
|
|
121
|
+
}
|
|
122
|
+
// Set the blob in the storage connector, which may now be encrypted
|
|
123
|
+
const blobId = await blobStorageConnector.set(storeBlob);
|
|
124
|
+
// Now store the entry in entity storage
|
|
125
|
+
const blobEntry = {
|
|
126
|
+
id: blobId,
|
|
127
|
+
dateCreated: new Date(Date.now()).toISOString(),
|
|
128
|
+
blobSize,
|
|
129
|
+
blobHash,
|
|
130
|
+
encodingFormat,
|
|
131
|
+
fileExtension,
|
|
132
|
+
metadata,
|
|
133
|
+
isEncrypted: encryptionEnabled,
|
|
134
|
+
compression: options?.compress
|
|
135
|
+
};
|
|
136
|
+
await this._entryEntityStorage.set(blobEntry);
|
|
137
|
+
return blobId;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "createFailed", undefined, error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get the blob entry.
|
|
145
|
+
* @param id The id of the blob to get in urn format.
|
|
146
|
+
* @param options Optional options for the retrieval of the blob.
|
|
147
|
+
* @param options.includeContent Include the content, or just get the metadata.
|
|
148
|
+
* @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
|
|
149
|
+
* @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
|
|
150
|
+
* @returns The entry and data for the blob if it can be found.
|
|
151
|
+
* @throws Not found error if the blob cannot be found.
|
|
152
|
+
*/
|
|
153
|
+
async get(id, options) {
|
|
154
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
155
|
+
const includeContent = options?.includeContent ?? false;
|
|
156
|
+
const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
|
|
157
|
+
try {
|
|
158
|
+
const blobEntry = await this.internalGet(id);
|
|
159
|
+
let returnBlob;
|
|
160
|
+
if (includeContent) {
|
|
161
|
+
const blobStorageConnector = this.getConnector(id);
|
|
162
|
+
returnBlob = await blobStorageConnector.get(id);
|
|
163
|
+
if (Is.undefined(returnBlob)) {
|
|
164
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
165
|
+
}
|
|
166
|
+
// If the data is encrypted then decrypt it.
|
|
167
|
+
const decryptionEnabled = blobEntry.isEncrypted && Is.stringValue(vaultKeyId);
|
|
168
|
+
if (decryptionEnabled) {
|
|
169
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
170
|
+
ContextIdHelper.guard(contextIds, ContextIdKeys.Organization);
|
|
171
|
+
if (Is.empty(this._vaultConnector)) {
|
|
172
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "vaultConnectorNotConfigured");
|
|
173
|
+
}
|
|
174
|
+
returnBlob = await this._vaultConnector.decrypt(`${contextIds[ContextIdKeys.Organization]}/${vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
|
|
175
|
+
}
|
|
176
|
+
if (!Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {
|
|
177
|
+
returnBlob = await Compression.decompress(returnBlob, blobEntry.compression);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
|
|
181
|
+
const result = await JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "getFailed", undefined, error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Update the blob with metadata.
|
|
190
|
+
* @param id The id of the blob entry to update.
|
|
191
|
+
* @param encodingFormat Mime type for the blob, will be detected if left undefined.
|
|
192
|
+
* @param fileExtension Extension for the blob, will be detected if left undefined.
|
|
193
|
+
* @param metadata Data for the custom metadata as JSON-LD.
|
|
194
|
+
* @returns Nothing.
|
|
195
|
+
* @throws Not found error if the blob cannot be found.
|
|
196
|
+
*/
|
|
197
|
+
async update(id, encodingFormat, fileExtension, metadata) {
|
|
198
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
199
|
+
try {
|
|
200
|
+
const blobEntry = await this._entryEntityStorage.get(id);
|
|
201
|
+
if (Is.undefined(blobEntry)) {
|
|
202
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
203
|
+
}
|
|
204
|
+
if (Is.object(metadata)) {
|
|
205
|
+
const validationFailures = [];
|
|
206
|
+
await JsonLdHelper.validate(metadata, validationFailures);
|
|
207
|
+
Validation.asValidationError(BlobStorageService.CLASS_NAME, "metadata", validationFailures);
|
|
208
|
+
}
|
|
209
|
+
// Now store the entry in entity storage
|
|
210
|
+
const updatedBlobEntry = {
|
|
211
|
+
id: blobEntry.id,
|
|
212
|
+
dateCreated: blobEntry.dateCreated,
|
|
213
|
+
dateModified: new Date(Date.now()).toISOString(),
|
|
214
|
+
blobSize: blobEntry.blobSize,
|
|
215
|
+
blobHash: blobEntry.blobHash,
|
|
216
|
+
encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
|
|
217
|
+
fileExtension: fileExtension ?? blobEntry.fileExtension,
|
|
218
|
+
metadata: metadata ?? blobEntry.metadata,
|
|
219
|
+
isEncrypted: blobEntry.isEncrypted,
|
|
220
|
+
compression: blobEntry.compression
|
|
221
|
+
};
|
|
222
|
+
await this._entryEntityStorage.set(updatedBlobEntry);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "updateFailed", undefined, error);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Remove the blob.
|
|
230
|
+
* @param id The id of the blob to remove in urn format.
|
|
231
|
+
* @returns Nothing.
|
|
232
|
+
*/
|
|
233
|
+
async remove(id) {
|
|
234
|
+
Urn.guard(BlobStorageService.CLASS_NAME, "id", id);
|
|
235
|
+
try {
|
|
236
|
+
const blobStorageConnector = this.getConnector(id);
|
|
237
|
+
await this._entryEntityStorage.remove(id);
|
|
238
|
+
const removed = await blobStorageConnector.remove(id);
|
|
239
|
+
if (!removed) {
|
|
240
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "blobNotFound", id);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "removeFailed", undefined, error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Query all the blob storage entries which match the conditions.
|
|
249
|
+
* @param conditions The conditions to match for the entries.
|
|
250
|
+
* @param orderBy The order for the results, defaults to created.
|
|
251
|
+
* @param orderByDirection The direction for the order, defaults to descending.
|
|
252
|
+
* @param cursor The cursor to request the next page of entries.
|
|
253
|
+
* @param limit The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
|
|
254
|
+
* @returns All the entries for the storage matching the conditions,
|
|
255
|
+
* and a cursor which can be used to request more entities.
|
|
256
|
+
*/
|
|
257
|
+
async query(conditions, orderBy, orderByDirection, cursor, limit) {
|
|
258
|
+
const orderProperty = orderBy ?? "dateCreated";
|
|
259
|
+
const orderDirection = orderByDirection ?? SortDirection.Descending;
|
|
260
|
+
const result = await this._entryEntityStorage.query(conditions, [
|
|
261
|
+
{
|
|
262
|
+
property: orderProperty,
|
|
263
|
+
sortDirection: orderDirection
|
|
264
|
+
}
|
|
265
|
+
], undefined, cursor, limit);
|
|
266
|
+
let context = [
|
|
267
|
+
SchemaOrgContexts.Namespace,
|
|
268
|
+
BlobStorageContexts.Namespace,
|
|
269
|
+
BlobStorageContexts.NamespaceCommon
|
|
270
|
+
];
|
|
271
|
+
const entriesJsonLd = [];
|
|
272
|
+
for (const entry of result.entities) {
|
|
273
|
+
// The entries are never Partial as we don't allow custom property requests.
|
|
274
|
+
entriesJsonLd.push(this.entryToJsonLd(entry));
|
|
275
|
+
context = JsonLdProcessor.combineContexts(context, entry.metadata?.["@context"]);
|
|
276
|
+
}
|
|
277
|
+
const jsonLd = {
|
|
278
|
+
"@context": context,
|
|
279
|
+
type: SchemaOrgTypes.ItemList,
|
|
280
|
+
[SchemaOrgTypes.ItemListElement]: entriesJsonLd,
|
|
281
|
+
[SchemaOrgTypes.NextItem]: result.cursor
|
|
282
|
+
};
|
|
283
|
+
return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Get the connector from the uri.
|
|
287
|
+
* @param id The id of the blob storage item in urn format.
|
|
288
|
+
* @returns The connector.
|
|
289
|
+
* @internal
|
|
290
|
+
*/
|
|
291
|
+
getConnector(id) {
|
|
292
|
+
const idUri = Urn.fromValidString(id);
|
|
293
|
+
if (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {
|
|
294
|
+
throw new GeneralError(BlobStorageService.CLASS_NAME, "namespaceMismatch", {
|
|
295
|
+
namespace: BlobStorageService._NAMESPACE,
|
|
296
|
+
id
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
return BlobStorageConnectorFactory.get(idUri.namespaceMethod());
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get an entity.
|
|
303
|
+
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
304
|
+
* @param secondaryIndex Get the item using a secondary index.
|
|
305
|
+
* @param partitionKey The optional partition key to use.
|
|
306
|
+
* @returns The object if it can be found or throws.
|
|
307
|
+
* @internal
|
|
308
|
+
*/
|
|
309
|
+
async internalGet(id) {
|
|
310
|
+
const schema = this._entryEntityStorage.getSchema();
|
|
311
|
+
const primaryKey = EntitySchemaHelper.getPrimaryKey(schema);
|
|
312
|
+
const conditions = [
|
|
313
|
+
{
|
|
314
|
+
property: primaryKey.property,
|
|
315
|
+
comparison: ComparisonOperator.Equals,
|
|
316
|
+
value: id
|
|
317
|
+
}
|
|
318
|
+
];
|
|
319
|
+
const results = await this._entryEntityStorage.query({
|
|
320
|
+
conditions,
|
|
321
|
+
logicalOperator: LogicalOperator.And
|
|
322
|
+
}, undefined, undefined, undefined, 1);
|
|
323
|
+
const entity = results.entities[0];
|
|
324
|
+
if (Is.empty(entity)) {
|
|
325
|
+
throw new NotFoundError(BlobStorageService.CLASS_NAME, "entityNotFound", id);
|
|
326
|
+
}
|
|
327
|
+
return entity;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Convert the entry to JSON-LD.
|
|
331
|
+
* @param entry The entry to convert.
|
|
332
|
+
* @param blob The optional blob to return.
|
|
333
|
+
* @returns The JSON-LD representation of the entry.
|
|
334
|
+
* @internal
|
|
335
|
+
*/
|
|
336
|
+
entryToJsonLd(entry, blob) {
|
|
337
|
+
const jsonLd = {
|
|
338
|
+
"@context": JsonLdProcessor.combineContexts([
|
|
339
|
+
BlobStorageContexts.Namespace,
|
|
340
|
+
BlobStorageContexts.NamespaceCommon,
|
|
341
|
+
SchemaOrgContexts.Namespace
|
|
342
|
+
], entry?.metadata?.["@context"]),
|
|
343
|
+
id: entry.id,
|
|
344
|
+
type: BlobStorageTypes.Entry,
|
|
345
|
+
dateCreated: entry.dateCreated,
|
|
346
|
+
dateModified: entry.dateModified,
|
|
347
|
+
blobSize: entry.blobSize,
|
|
348
|
+
blobHash: entry.blobHash,
|
|
349
|
+
encodingFormat: entry?.encodingFormat,
|
|
350
|
+
fileExtension: entry?.fileExtension,
|
|
351
|
+
metadata: entry?.metadata,
|
|
352
|
+
blob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined,
|
|
353
|
+
isEncrypted: entry.isEncrypted,
|
|
354
|
+
compression: entry.compression
|
|
355
|
+
};
|
|
356
|
+
return jsonLd;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=blobStorageService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobStorageService.js","sourceRoot":"","sources":["../../src/blobStorageService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport {\n\tBlobStorageConnectorFactory,\n\tBlobStorageContexts,\n\tBlobStorageTypes,\n\ttype BlobStorageCompressionType,\n\ttype IBlobStorageComponent,\n\ttype IBlobStorageConnector,\n\ttype IBlobStorageEntry,\n\ttype IBlobStorageEntryList\n} from \"@twin.org/blob-storage-models\";\nimport { ContextIdHelper, ContextIdKeys, ContextIdStore } from \"@twin.org/context\";\nimport {\n\tCompression,\n\tConverter,\n\tGeneralError,\n\tGuards,\n\tIs,\n\tNotFoundError,\n\tUrn,\n\tValidation,\n\ttype IValidationFailure\n} from \"@twin.org/core\";\nimport { Sha256 } from \"@twin.org/crypto\";\nimport { JsonLdHelper, JsonLdProcessor, type IJsonLdNodeObject } from \"@twin.org/data-json-ld\";\nimport {\n\tComparisonOperator,\n\tEntitySchemaHelper,\n\tLogicalOperator,\n\tSortDirection,\n\ttype EntityCondition\n} from \"@twin.org/entity\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport {\n\tSchemaOrgContexts,\n\tSchemaOrgDataTypes,\n\tSchemaOrgTypes\n} from \"@twin.org/standards-schema-org\";\nimport {\n\tVaultConnectorFactory,\n\tVaultEncryptionType,\n\ttype IVaultConnector\n} from \"@twin.org/vault-models\";\nimport { MimeTypeHelper } from \"@twin.org/web\";\nimport type { BlobStorageEntry } from \"./entities/blobStorageEntry.js\";\nimport type { IBlobStorageServiceConstructorOptions } from \"./models/IBlobStorageServiceConstructorOptions.js\";\n\n/**\n * Service for performing blob storage operations to a connector.\n */\nexport class BlobStorageService implements IBlobStorageComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<BlobStorageService>();\n\n\t/**\n\t * The namespace supported by the blob storage service.\n\t * @internal\n\t */\n\tprivate static readonly _NAMESPACE: string = \"blob\";\n\n\t/**\n\t * The namespace of the default storage connector to use.\n\t * Defaults to the first entry in the factory if not provided.\n\t * @internal\n\t */\n\tprivate readonly _defaultNamespace: string;\n\n\t/**\n\t * The storage connector for the metadata.\n\t * @internal\n\t */\n\tprivate readonly _entryEntityStorage: IEntityStorageConnector<BlobStorageEntry>;\n\n\t/**\n\t * The vault connector for the encryption, can be undefined if no encryption required.\n\t * @internal\n\t */\n\tprivate readonly _vaultConnector?: IVaultConnector;\n\n\t/**\n\t * The id of the vault key to use for encryption if the service has a vault connector configured.\n\t * @internal\n\t */\n\tprivate readonly _vaultKeyId: string | undefined;\n\n\t/**\n\t * Create a new instance of BlobStorageService.\n\t * @param options The options for the service.\n\t */\n\tconstructor(options?: IBlobStorageServiceConstructorOptions) {\n\t\tconst names = BlobStorageConnectorFactory.names();\n\t\tif (names.length === 0) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"noConnectors\");\n\t\t}\n\n\t\tthis._entryEntityStorage = EntityStorageConnectorFactory.get(\n\t\t\toptions?.entryEntityStorageType ?? \"blob-storage-entry\"\n\t\t);\n\t\tif (Is.stringValue(options?.vaultConnectorType)) {\n\t\t\tthis._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType);\n\t\t}\n\n\t\tthis._defaultNamespace = options?.config?.defaultNamespace ?? names[0];\n\t\tthis._vaultKeyId = options?.config?.vaultKeyId;\n\n\t\tSchemaOrgDataTypes.registerRedirects();\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 BlobStorageService.CLASS_NAME;\n\t}\n\n\t/**\n\t * Create the blob with some metadata.\n\t * @param blob The data for the blob in base64 format.\n\t * @param encodingFormat Mime type for the blob, will be detected if left undefined.\n\t * @param fileExtension Extension for the blob, will be detected if left undefined.\n\t * @param metadata Data for the custom metadata as JSON-LD.\n\t * @param options Optional options for the creation of the blob.\n\t * @param options.disableEncryption Disables encryption if enabled by default.\n\t * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.\n\t * @param options.compress Optional compression type to use for the blob, defaults to no compression.\n\t * @param options.namespace The namespace to use for storing, defaults to component configured namespace.\n\t * @returns The id of the stored blob in urn format.\n\t */\n\tpublic async create(\n\t\tblob: string,\n\t\tencodingFormat?: string,\n\t\tfileExtension?: string,\n\t\tmetadata?: IJsonLdNodeObject,\n\t\toptions?: {\n\t\t\tdisableEncryption?: boolean;\n\t\t\toverrideVaultKeyId?: string;\n\t\t\tcompress?: BlobStorageCompressionType;\n\t\t\tnamespace?: string;\n\t\t}\n\t): Promise<string> {\n\t\tGuards.stringBase64(BlobStorageService.CLASS_NAME, nameof(blob), blob);\n\n\t\tconst disableEncryption = options?.disableEncryption ?? false;\n\t\tconst vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;\n\t\tconst encryptionEnabled = !disableEncryption && Is.stringValue(vaultKeyId);\n\n\t\ttry {\n\t\t\tconst connectorNamespace = options?.namespace ?? this._defaultNamespace;\n\n\t\t\tconst blobStorageConnector =\n\t\t\t\tBlobStorageConnectorFactory.get<IBlobStorageConnector>(connectorNamespace);\n\n\t\t\t// Convert the base64 data into bytes\n\t\t\tlet storeBlob = Converter.base64ToBytes(blob);\n\t\t\tconst blobSize = storeBlob.length;\n\n\t\t\t// See if we can detect the mime type and default extension for the data.\n\t\t\t// If not already supplied by the caller. We have to perform this operation\n\t\t\t// on the unencrypted data.\n\t\t\tif (!Is.stringValue(encodingFormat)) {\n\t\t\t\tencodingFormat = await MimeTypeHelper.detect(storeBlob);\n\t\t\t}\n\n\t\t\tif (!Is.stringValue(fileExtension) && Is.stringValue(encodingFormat)) {\n\t\t\t\tfileExtension = MimeTypeHelper.defaultExtension(encodingFormat);\n\t\t\t}\n\n\t\t\tif (Is.object(metadata)) {\n\t\t\t\tconst validationFailures: IValidationFailure[] = [];\n\t\t\t\tawait JsonLdHelper.validate(metadata, validationFailures);\n\t\t\t\tValidation.asValidationError(\n\t\t\t\t\tBlobStorageService.CLASS_NAME,\n\t\t\t\t\tnameof(metadata),\n\t\t\t\t\tvalidationFailures\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;\n\n\t\t\tif (!Is.empty(options?.compress)) {\n\t\t\t\tstoreBlob = await Compression.compress(storeBlob, options.compress);\n\t\t\t}\n\n\t\t\t// If we have a vault connector then encrypt the data.\n\t\t\tif (encryptionEnabled) {\n\t\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Organization);\n\n\t\t\t\tif (Is.empty(this._vaultConnector)) {\n\t\t\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"vaultConnectorNotConfigured\");\n\t\t\t\t}\n\t\t\t\tstoreBlob = await this._vaultConnector.encrypt(\n\t\t\t\t\t`${contextIds[ContextIdKeys.Organization]}/${vaultKeyId}`,\n\t\t\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\t\t\tstoreBlob\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Set the blob in the storage connector, which may now be encrypted\n\t\t\tconst blobId = await blobStorageConnector.set(storeBlob);\n\n\t\t\t// Now store the entry in entity storage\n\t\t\tconst blobEntry: BlobStorageEntry = {\n\t\t\t\tid: blobId,\n\t\t\t\tdateCreated: new Date(Date.now()).toISOString(),\n\t\t\t\tblobSize,\n\t\t\t\tblobHash,\n\t\t\t\tencodingFormat,\n\t\t\t\tfileExtension,\n\t\t\t\tmetadata,\n\t\t\t\tisEncrypted: encryptionEnabled,\n\t\t\t\tcompression: options?.compress\n\t\t\t};\n\n\t\t\tawait this._entryEntityStorage.set(blobEntry);\n\n\t\t\treturn blobId;\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"createFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Get the blob entry.\n\t * @param id The id of the blob to get in urn format.\n\t * @param options Optional options for the retrieval of the blob.\n\t * @param options.includeContent Include the content, or just get the metadata.\n\t * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.\n\t * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.\n\t * @returns The entry and data for the blob if it can be found.\n\t * @throws Not found error if the blob cannot be found.\n\t */\n\tpublic async get(\n\t\tid: string,\n\t\toptions?: {\n\t\t\tincludeContent?: boolean;\n\t\t\tdecompress?: boolean;\n\t\t\toverrideVaultKeyId?: string;\n\t\t}\n\t): Promise<IBlobStorageEntry> {\n\t\tUrn.guard(BlobStorageService.CLASS_NAME, nameof(id), id);\n\n\t\tconst includeContent = options?.includeContent ?? false;\n\t\tconst vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;\n\n\t\ttry {\n\t\t\tconst blobEntry = await this.internalGet(id);\n\n\t\t\tlet returnBlob: Uint8Array | undefined;\n\t\t\tif (includeContent) {\n\t\t\t\tconst blobStorageConnector = this.getConnector(id);\n\t\t\t\treturnBlob = await blobStorageConnector.get(id);\n\t\t\t\tif (Is.undefined(returnBlob)) {\n\t\t\t\t\tthrow new NotFoundError(BlobStorageService.CLASS_NAME, \"blobNotFound\", id);\n\t\t\t\t}\n\n\t\t\t\t// If the data is encrypted then decrypt it.\n\t\t\t\tconst decryptionEnabled = blobEntry.isEncrypted && Is.stringValue(vaultKeyId);\n\t\t\t\tif (decryptionEnabled) {\n\t\t\t\t\tconst contextIds = await ContextIdStore.getContextIds();\n\t\t\t\t\tContextIdHelper.guard(contextIds, ContextIdKeys.Organization);\n\n\t\t\t\t\tif (Is.empty(this._vaultConnector)) {\n\t\t\t\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"vaultConnectorNotConfigured\");\n\t\t\t\t\t}\n\n\t\t\t\t\treturnBlob = await this._vaultConnector.decrypt(\n\t\t\t\t\t\t`${contextIds[ContextIdKeys.Organization]}/${vaultKeyId}`,\n\t\t\t\t\t\tVaultEncryptionType.ChaCha20Poly1305,\n\t\t\t\t\t\treturnBlob\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (!Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {\n\t\t\t\t\treturnBlob = await Compression.decompress(returnBlob, blobEntry.compression);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst jsonLd = this.entryToJsonLd(blobEntry, returnBlob);\n\t\t\tconst result = await JsonLdProcessor.compact(jsonLd, jsonLd[\"@context\"]);\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"getFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Update the blob with metadata.\n\t * @param id The id of the blob entry to update.\n\t * @param encodingFormat Mime type for the blob, will be detected if left undefined.\n\t * @param fileExtension Extension for the blob, will be detected if left undefined.\n\t * @param metadata Data for the custom metadata as JSON-LD.\n\t * @returns Nothing.\n\t * @throws Not found error if the blob cannot be found.\n\t */\n\tpublic async update(\n\t\tid: string,\n\t\tencodingFormat?: string,\n\t\tfileExtension?: string,\n\t\tmetadata?: IJsonLdNodeObject\n\t): Promise<void> {\n\t\tUrn.guard(BlobStorageService.CLASS_NAME, nameof(id), id);\n\n\t\ttry {\n\t\t\tconst blobEntry = await this._entryEntityStorage.get(id);\n\n\t\t\tif (Is.undefined(blobEntry)) {\n\t\t\t\tthrow new NotFoundError(BlobStorageService.CLASS_NAME, \"blobNotFound\", id);\n\t\t\t}\n\n\t\t\tif (Is.object(metadata)) {\n\t\t\t\tconst validationFailures: IValidationFailure[] = [];\n\t\t\t\tawait JsonLdHelper.validate(metadata, validationFailures);\n\t\t\t\tValidation.asValidationError(\n\t\t\t\t\tBlobStorageService.CLASS_NAME,\n\t\t\t\t\tnameof(metadata),\n\t\t\t\t\tvalidationFailures\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Now store the entry in entity storage\n\t\t\tconst updatedBlobEntry: BlobStorageEntry = {\n\t\t\t\tid: blobEntry.id,\n\t\t\t\tdateCreated: blobEntry.dateCreated,\n\t\t\t\tdateModified: new Date(Date.now()).toISOString(),\n\t\t\t\tblobSize: blobEntry.blobSize,\n\t\t\t\tblobHash: blobEntry.blobHash,\n\t\t\t\tencodingFormat: encodingFormat ?? blobEntry.encodingFormat,\n\t\t\t\tfileExtension: fileExtension ?? blobEntry.fileExtension,\n\t\t\t\tmetadata: metadata ?? blobEntry.metadata,\n\t\t\t\tisEncrypted: blobEntry.isEncrypted,\n\t\t\t\tcompression: blobEntry.compression\n\t\t\t};\n\n\t\t\tawait this._entryEntityStorage.set(updatedBlobEntry);\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"updateFailed\", undefined, error);\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 Nothing.\n\t */\n\tpublic async remove(id: string): Promise<void> {\n\t\tUrn.guard(BlobStorageService.CLASS_NAME, nameof(id), id);\n\n\t\ttry {\n\t\t\tconst blobStorageConnector = this.getConnector(id);\n\n\t\t\tawait this._entryEntityStorage.remove(id);\n\n\t\t\tconst removed = await blobStorageConnector.remove(id);\n\n\t\t\tif (!removed) {\n\t\t\t\tthrow new NotFoundError(BlobStorageService.CLASS_NAME, \"blobNotFound\", id);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"removeFailed\", undefined, error);\n\t\t}\n\t}\n\n\t/**\n\t * Query all the blob storage entries which match the conditions.\n\t * @param conditions The conditions to match for the entries.\n\t * @param orderBy The order for the results, defaults to created.\n\t * @param orderByDirection The direction for the order, defaults to descending.\n\t * @param cursor The cursor to request the next page of entries.\n\t * @param limit The suggested number of entries to return in each chunk, in some scenarios can return a different amount.\n\t * @returns All the entries for the storage matching the conditions,\n\t * and a cursor which can be used to request more entities.\n\t */\n\tpublic async query(\n\t\tconditions?: EntityCondition<IBlobStorageEntry>,\n\t\torderBy?: keyof Pick<IBlobStorageEntry, \"dateCreated\" | \"dateModified\">,\n\t\torderByDirection?: SortDirection,\n\t\tcursor?: string,\n\t\tlimit?: number\n\t): Promise<IBlobStorageEntryList> {\n\t\tconst orderProperty = orderBy ?? \"dateCreated\";\n\t\tconst orderDirection = orderByDirection ?? SortDirection.Descending;\n\n\t\tconst result = await this._entryEntityStorage.query(\n\t\t\tconditions,\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tproperty: orderProperty,\n\t\t\t\t\tsortDirection: orderDirection\n\t\t\t\t}\n\t\t\t],\n\t\t\tundefined,\n\t\t\tcursor,\n\t\t\tlimit\n\t\t);\n\n\t\tlet context: IBlobStorageEntryList[\"@context\"] = [\n\t\t\tSchemaOrgContexts.Namespace,\n\t\t\tBlobStorageContexts.Namespace,\n\t\t\tBlobStorageContexts.NamespaceCommon\n\t\t];\n\t\tconst entriesJsonLd = [];\n\n\t\tfor (const entry of result.entities) {\n\t\t\t// The entries are never Partial as we don't allow custom property requests.\n\t\t\tentriesJsonLd.push(this.entryToJsonLd(entry as BlobStorageEntry));\n\t\t\tcontext = JsonLdProcessor.combineContexts(\n\t\t\t\tcontext,\n\t\t\t\tentry.metadata?.[\"@context\"]\n\t\t\t) as IBlobStorageEntryList[\"@context\"];\n\t\t}\n\n\t\tconst jsonLd: IBlobStorageEntryList = {\n\t\t\t\"@context\": context,\n\t\t\ttype: SchemaOrgTypes.ItemList,\n\t\t\t[SchemaOrgTypes.ItemListElement]: entriesJsonLd,\n\t\t\t[SchemaOrgTypes.NextItem]: result.cursor\n\t\t};\n\n\t\treturn JsonLdProcessor.compact(jsonLd, jsonLd[\"@context\"]);\n\t}\n\n\t/**\n\t * Get the connector from the uri.\n\t * @param id The id of the blob storage item in urn format.\n\t * @returns The connector.\n\t * @internal\n\t */\n\tprivate getConnector(id: string): IBlobStorageConnector {\n\t\tconst idUri = Urn.fromValidString(id);\n\n\t\tif (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {\n\t\t\tthrow new GeneralError(BlobStorageService.CLASS_NAME, \"namespaceMismatch\", {\n\t\t\t\tnamespace: BlobStorageService._NAMESPACE,\n\t\t\t\tid\n\t\t\t});\n\t\t}\n\n\t\treturn BlobStorageConnectorFactory.get<IBlobStorageConnector>(idUri.namespaceMethod());\n\t}\n\n\t/**\n\t * Get an entity.\n\t * @param id The id of the entity to get, or the index value if secondaryIndex is set.\n\t * @param secondaryIndex Get the item using a secondary index.\n\t * @param partitionKey The optional partition key to use.\n\t * @returns The object if it can be found or throws.\n\t * @internal\n\t */\n\tprivate async internalGet(id: string): Promise<BlobStorageEntry> {\n\t\tconst schema = this._entryEntityStorage.getSchema();\n\t\tconst primaryKey = EntitySchemaHelper.getPrimaryKey(schema);\n\n\t\tconst conditions: EntityCondition<BlobStorageEntry>[] = [\n\t\t\t{\n\t\t\t\tproperty: primaryKey.property,\n\t\t\t\tcomparison: ComparisonOperator.Equals,\n\t\t\t\tvalue: id\n\t\t\t}\n\t\t];\n\n\t\tconst results = await this._entryEntityStorage.query(\n\t\t\t{\n\t\t\t\tconditions,\n\t\t\t\tlogicalOperator: LogicalOperator.And\n\t\t\t},\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\t1\n\t\t);\n\n\t\tconst entity = results.entities[0] as BlobStorageEntry;\n\n\t\tif (Is.empty(entity)) {\n\t\t\tthrow new NotFoundError(BlobStorageService.CLASS_NAME, \"entityNotFound\", id);\n\t\t}\n\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Convert the entry to JSON-LD.\n\t * @param entry The entry to convert.\n\t * @param blob The optional blob to return.\n\t * @returns The JSON-LD representation of the entry.\n\t * @internal\n\t */\n\tprivate entryToJsonLd(entry: BlobStorageEntry, blob?: Uint8Array): IBlobStorageEntry {\n\t\tconst jsonLd: IBlobStorageEntry = {\n\t\t\t\"@context\": JsonLdProcessor.combineContexts(\n\t\t\t\t[\n\t\t\t\t\tBlobStorageContexts.Namespace,\n\t\t\t\t\tBlobStorageContexts.NamespaceCommon,\n\t\t\t\t\tSchemaOrgContexts.Namespace\n\t\t\t\t],\n\t\t\t\tentry?.metadata?.[\"@context\"]\n\t\t\t) as IBlobStorageEntry[\"@context\"],\n\t\t\tid: entry.id,\n\t\t\ttype: BlobStorageTypes.Entry,\n\t\t\tdateCreated: entry.dateCreated,\n\t\t\tdateModified: entry.dateModified,\n\t\t\tblobSize: entry.blobSize,\n\t\t\tblobHash: entry.blobHash,\n\t\t\tencodingFormat: entry?.encodingFormat,\n\t\t\tfileExtension: entry?.fileExtension,\n\t\t\tmetadata: entry?.metadata,\n\t\t\tblob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined,\n\t\t\tisEncrypted: entry.isEncrypted,\n\t\t\tcompression: entry.compression\n\t\t};\n\n\t\treturn jsonLd;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { entity, property, SortDirection } from "@twin.org/entity";
|
|
2
|
+
/**
|
|
3
|
+
* Class representing entry for the blob storage.
|
|
4
|
+
*/
|
|
5
|
+
let BlobStorageEntry = class BlobStorageEntry {
|
|
6
|
+
/**
|
|
7
|
+
* The id for the blob.
|
|
8
|
+
*/
|
|
9
|
+
id;
|
|
10
|
+
/**
|
|
11
|
+
* The date/time when the entry was created.
|
|
12
|
+
*/
|
|
13
|
+
dateCreated;
|
|
14
|
+
/**
|
|
15
|
+
* The date/time when the entry was modified.
|
|
16
|
+
*/
|
|
17
|
+
dateModified;
|
|
18
|
+
/**
|
|
19
|
+
* The length of the data in the blob.
|
|
20
|
+
*/
|
|
21
|
+
blobSize;
|
|
22
|
+
/**
|
|
23
|
+
* The hash of the data in the blob.
|
|
24
|
+
*/
|
|
25
|
+
blobHash;
|
|
26
|
+
/**
|
|
27
|
+
* The mime type for the blob.
|
|
28
|
+
*/
|
|
29
|
+
encodingFormat;
|
|
30
|
+
/**
|
|
31
|
+
* The extension.
|
|
32
|
+
*/
|
|
33
|
+
fileExtension;
|
|
34
|
+
/**
|
|
35
|
+
* The metadata for the blob as JSON-LD.
|
|
36
|
+
*/
|
|
37
|
+
metadata;
|
|
38
|
+
/**
|
|
39
|
+
* Is the entry encrypted.
|
|
40
|
+
*/
|
|
41
|
+
isEncrypted;
|
|
42
|
+
/**
|
|
43
|
+
* Is the entry compressed.
|
|
44
|
+
*/
|
|
45
|
+
compression;
|
|
46
|
+
};
|
|
47
|
+
__decorate([
|
|
48
|
+
property({ type: "string", isPrimary: true }),
|
|
49
|
+
__metadata("design:type", String)
|
|
50
|
+
], BlobStorageEntry.prototype, "id", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
|
|
53
|
+
__metadata("design:type", String)
|
|
54
|
+
], BlobStorageEntry.prototype, "dateCreated", void 0);
|
|
55
|
+
__decorate([
|
|
56
|
+
property({
|
|
57
|
+
type: "string",
|
|
58
|
+
format: "date-time",
|
|
59
|
+
sortDirection: SortDirection.Descending,
|
|
60
|
+
optional: true
|
|
61
|
+
}),
|
|
62
|
+
__metadata("design:type", String)
|
|
63
|
+
], BlobStorageEntry.prototype, "dateModified", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
property({ type: "number" }),
|
|
66
|
+
__metadata("design:type", Number)
|
|
67
|
+
], BlobStorageEntry.prototype, "blobSize", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
property({ type: "string" }),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], BlobStorageEntry.prototype, "blobHash", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
property({ type: "string", optional: true }),
|
|
74
|
+
__metadata("design:type", String)
|
|
75
|
+
], BlobStorageEntry.prototype, "encodingFormat", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
property({ type: "string", optional: true }),
|
|
78
|
+
__metadata("design:type", String)
|
|
79
|
+
], BlobStorageEntry.prototype, "fileExtension", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
|
|
82
|
+
__metadata("design:type", Object)
|
|
83
|
+
], BlobStorageEntry.prototype, "metadata", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
property({ type: "boolean" }),
|
|
86
|
+
__metadata("design:type", Boolean)
|
|
87
|
+
], BlobStorageEntry.prototype, "isEncrypted", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
property({ type: "string", optional: true }),
|
|
90
|
+
__metadata("design:type", String)
|
|
91
|
+
], BlobStorageEntry.prototype, "compression", void 0);
|
|
92
|
+
BlobStorageEntry = __decorate([
|
|
93
|
+
entity()
|
|
94
|
+
], BlobStorageEntry);
|
|
95
|
+
export { BlobStorageEntry };
|
|
96
|
+
//# sourceMappingURL=blobStorageEntry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blobStorageEntry.js","sourceRoot":"","sources":["../../../src/entities/blobStorageEntry.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEnE;;GAEG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC5B;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,WAAW,CAAU;IAE5B;;OAEG;IAOI,YAAY,CAAU;IAE7B;;OAEG;IAEI,QAAQ,CAAU;IAEzB;;OAEG;IAEI,QAAQ,CAAU;IAEzB;;OAEG;IAEI,cAAc,CAAU;IAE/B;;OAEG;IAEI,aAAa,CAAU;IAE9B;;OAEG;IAEI,QAAQ,CAAqB;IAEpC;;OAEG;IAEI,WAAW,CAAW;IAE7B;;OAEG;IAEI,WAAW,CAA8B;CAChD,CAAA;AA5DO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;4CAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,CAAC,UAAU,EAAE,CAAC;;qDAC/D;AAWrB;IANN,QAAQ,CAAC;QACT,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,WAAW;QACnB,aAAa,EAAE,aAAa,CAAC,UAAU;QACvC,QAAQ,EAAE,IAAI;KACd,CAAC;;sDAC2B;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;kDACJ;AAMlB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;;kDACJ;AAMlB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;wDACd;AAMxB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;uDACf;AAMvB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDAC3C;AAM7B;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;qDACD;AAMtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDACG;AAhEpC,gBAAgB;IAD5B,MAAM,EAAE;GACI,gBAAgB,CAiE5B","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { BlobStorageCompressionType } from \"@twin.org/blob-storage-models\";\nimport type { IJsonLdNodeObject } from \"@twin.org/data-json-ld\";\nimport { entity, property, SortDirection } from \"@twin.org/entity\";\n\n/**\n * Class representing entry for the blob storage.\n */\n@entity()\nexport class BlobStorageEntry {\n\t/**\n\t * The id for the blob.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The date/time when the entry was created.\n\t */\n\t@property({ type: \"string\", format: \"date-time\", sortDirection: SortDirection.Descending })\n\tpublic dateCreated!: string;\n\n\t/**\n\t * The date/time when the entry was modified.\n\t */\n\t@property({\n\t\ttype: \"string\",\n\t\tformat: \"date-time\",\n\t\tsortDirection: SortDirection.Descending,\n\t\toptional: true\n\t})\n\tpublic dateModified?: string;\n\n\t/**\n\t * The length of the data in the blob.\n\t */\n\t@property({ type: \"number\" })\n\tpublic blobSize!: number;\n\n\t/**\n\t * The hash of the data in the blob.\n\t */\n\t@property({ type: \"string\" })\n\tpublic blobHash!: string;\n\n\t/**\n\t * The mime type for the blob.\n\t */\n\t@property({ type: \"string\", optional: true })\n\tpublic encodingFormat?: string;\n\n\t/**\n\t * The extension.\n\t */\n\t@property({ type: \"string\", optional: true })\n\tpublic fileExtension?: string;\n\n\t/**\n\t * The metadata for the blob as JSON-LD.\n\t */\n\t@property({ type: \"object\", itemTypeRef: \"IJsonLdNodeObject\", optional: true })\n\tpublic metadata?: IJsonLdNodeObject;\n\n\t/**\n\t * Is the entry encrypted.\n\t */\n\t@property({ type: \"boolean\" })\n\tpublic isEncrypted!: boolean;\n\n\t/**\n\t * Is the entry compressed.\n\t */\n\t@property({ type: \"string\", optional: true })\n\tpublic compression?: BlobStorageCompressionType;\n}\n"]}
|
package/dist/es/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
export * from "./blobStorageRoutes.js";
|
|
4
|
+
export * from "./blobStorageService.js";
|
|
5
|
+
export * from "./entities/blobStorageEntry.js";
|
|
6
|
+
export * from "./models/IBlobStorageServiceConfig.js";
|
|
7
|
+
export * from "./models/IBlobStorageServiceConstructorOptions.js";
|
|
8
|
+
export * from "./restEntryPoints.js";
|
|
9
|
+
export * from "./schema.js";
|
|
10
|
+
//# 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,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,mDAAmD,CAAC;AAClE,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./blobStorageRoutes.js\";\nexport * from \"./blobStorageService.js\";\nexport * from \"./entities/blobStorageEntry.js\";\nexport * from \"./models/IBlobStorageServiceConfig.js\";\nexport * from \"./models/IBlobStorageServiceConstructorOptions.js\";\nexport * from \"./restEntryPoints.js\";\nexport * from \"./schema.js\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IBlobStorageServiceConfig.js","sourceRoot":"","sources":["../../../src/models/IBlobStorageServiceConfig.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 blob storage service.\n */\nexport interface IBlobStorageServiceConfig {\n\t/**\n\t * The name of the vault key to use for encryption, if not configured no encryption will happen.\n\t */\n\tvaultKeyId?: string;\n\n\t/**\n\t * The namespace of the default storage connector to use.\n\t * Defaults to the first entry in the factory if not provided.\n\t */\n\tdefaultNamespace?: string;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IBlobStorageServiceConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IBlobStorageServiceConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IBlobStorageServiceConfig } from \"./IBlobStorageServiceConfig.js\";\n\n/**\n * Options for the Blob Storage Service constructor.\n */\nexport interface IBlobStorageServiceConstructorOptions {\n\t/**\n\t * The type of the storage connector for the metadata.\n\t * @default blob-storage-entry\n\t */\n\tentryEntityStorageType?: string;\n\n\t/**\n\t * The type of the vault connector for encryption.\n\t */\n\tvaultConnectorType?: string;\n\n\t/**\n\t * The configuration for the service.\n\t */\n\tconfig?: IBlobStorageServiceConfig;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { generateRestRoutesBlobStorage, tagsBlobStorage } from "./blobStorageRoutes.js";
|
|
2
|
+
/**
|
|
3
|
+
* These are dummy entry points for the blob storage service.
|
|
4
|
+
* In reality your application would create its own entry points based on the
|
|
5
|
+
* blob types it wants to store, using a custom defaultBaseRoute.
|
|
6
|
+
*/
|
|
7
|
+
export const restEntryPoints = [
|
|
8
|
+
{
|
|
9
|
+
name: "blob-storage",
|
|
10
|
+
defaultBaseRoute: "blob-storage",
|
|
11
|
+
tags: tagsBlobStorage,
|
|
12
|
+
generateRoutes: generateRestRoutesBlobStorage
|
|
13
|
+
}
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=restEntryPoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restEntryPoints.js","sourceRoot":"","sources":["../../src/restEntryPoints.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAExF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B;IACtD;QACC,IAAI,EAAE,cAAc;QACpB,gBAAgB,EAAE,cAAc;QAChC,IAAI,EAAE,eAAe;QACrB,cAAc,EAAE,6BAA6B;KAC7C;CACD,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IRestRouteEntryPoint } from \"@twin.org/api-models\";\nimport { generateRestRoutesBlobStorage, tagsBlobStorage } from \"./blobStorageRoutes.js\";\n\n/**\n * These are dummy entry points for the blob storage service.\n * In reality your application would create its own entry points based on the\n * blob types it wants to store, using a custom defaultBaseRoute.\n */\nexport const restEntryPoints: IRestRouteEntryPoint[] = [\n\t{\n\t\tname: \"blob-storage\",\n\t\tdefaultBaseRoute: \"blob-storage\",\n\t\ttags: tagsBlobStorage,\n\t\tgenerateRoutes: generateRestRoutesBlobStorage\n\t}\n];\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { EntitySchemaFactory, EntitySchemaHelper } from "@twin.org/entity";
|
|
4
|
+
import { BlobStorageEntry } from "./entities/blobStorageEntry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Initialize the schema for the blob storage entities.
|
|
7
|
+
*/
|
|
8
|
+
export function initSchema() {
|
|
9
|
+
EntitySchemaFactory.register("BlobStorageEntry", () => EntitySchemaHelper.getSchema(BlobStorageEntry));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAElE;;GAEG;AACH,MAAM,UAAU,UAAU;IACzB,mBAAmB,CAAC,QAAQ,qBAA6B,GAAG,EAAE,CAC7D,kBAAkB,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAC9C,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { EntitySchemaFactory, EntitySchemaHelper } from \"@twin.org/entity\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { BlobStorageEntry } from \"./entities/blobStorageEntry.js\";\n\n/**\n * Initialize the schema for the blob storage entities.\n */\nexport function initSchema(): void {\n\tEntitySchemaFactory.register(nameof<BlobStorageEntry>(), () =>\n\t\tEntitySchemaHelper.getSchema(BlobStorageEntry)\n\t);\n}\n"]}
|