@twin.org/blob-storage-service 0.0.1-next.7 → 0.0.1-next.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +200 -46
- package/dist/esm/index.mjs +201 -47
- package/dist/types/blobStorageRoutes.d.ts +7 -1
- package/dist/types/blobStorageService.d.ts +12 -6
- package/dist/types/entities/blobMetadata.d.ts +8 -0
- package/dist/types/models/IBlobStorageServiceConfig.d.ts +8 -0
- package/dist/types/restEntryPoints.d.ts +5 -0
- package/docs/changelog.md +1 -1
- package/docs/open-api/spec.json +10 -10
- package/docs/reference/classes/BlobMetadata.md +16 -0
- package/docs/reference/classes/BlobStorageService.md +30 -6
- package/docs/reference/functions/generateRestRoutesBlobStorage.md +13 -1
- package/docs/reference/interfaces/IBlobStorageServiceConfig.md +16 -0
- package/docs/reference/variables/restEntryPoints.md +4 -0
- package/package.json +2 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Guards, ComponentFactory, Is, Converter, GeneralError, Validation, Urn, NotFoundError } from '@twin.org/core';
|
|
1
|
+
import { StringHelper, Guards, ComponentFactory, Is, Converter, GeneralError, Validation, ObjectHelper, Urn, NotFoundError } from '@twin.org/core';
|
|
2
2
|
import { HttpStatusCode, HeaderTypes, MimeTypes, MimeTypeHelper } from '@twin.org/web';
|
|
3
3
|
import { BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
|
|
4
4
|
import { JsonLdHelper } from '@twin.org/data-json-ld';
|
|
5
|
+
import { ComparisonOperator, EntitySchemaHelper, LogicalOperator, property, entity, EntitySchemaFactory } from '@twin.org/entity';
|
|
5
6
|
import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
|
|
6
7
|
import { VaultConnectorFactory, VaultEncryptionType } from '@twin.org/vault-models';
|
|
7
|
-
import { property, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* The source used when communicating about these routes.
|
|
@@ -23,13 +23,19 @@ const tagsBlobStorage = [
|
|
|
23
23
|
* The REST routes for blob storage.
|
|
24
24
|
* @param baseRouteName Prefix to prepend to the paths.
|
|
25
25
|
* @param componentName The name of the component to use in the routes stored in the ComponentFactory.
|
|
26
|
+
* @param options Additional options for the routes.
|
|
27
|
+
* @param options.typeName Optional type name to use in the routes, defaults to Blob Storage.
|
|
28
|
+
* @param options.tagName Optional name to use in OpenAPI spec for tag.
|
|
26
29
|
* @returns The generated routes.
|
|
27
30
|
*/
|
|
28
|
-
function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
31
|
+
function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
|
|
32
|
+
const typeName = options?.typeName ?? "Blob Storage";
|
|
33
|
+
const lowerName = typeName.toLowerCase();
|
|
34
|
+
const camelTypeName = StringHelper.camelCase(typeName);
|
|
29
35
|
const blobStorageCreateRoute = {
|
|
30
|
-
operationId:
|
|
31
|
-
summary:
|
|
32
|
-
tag: tagsBlobStorage[0].name,
|
|
36
|
+
operationId: `${camelTypeName}Create`,
|
|
37
|
+
summary: `Create an entry in ${lowerName}`,
|
|
38
|
+
tag: options?.tagName ?? tagsBlobStorage[0].name,
|
|
33
39
|
method: "POST",
|
|
34
40
|
path: `${baseRouteName}/`,
|
|
35
41
|
handler: async (httpRequestContext, request) => blobStorageCreate(httpRequestContext, componentName, request),
|
|
@@ -37,7 +43,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
37
43
|
type: "IBlobStorageCreateRequest",
|
|
38
44
|
examples: [
|
|
39
45
|
{
|
|
40
|
-
id:
|
|
46
|
+
id: `${camelTypeName}CreateRequestExample`,
|
|
41
47
|
request: {
|
|
42
48
|
body: {
|
|
43
49
|
blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==",
|
|
@@ -56,7 +62,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
56
62
|
type: "ICreatedResponse",
|
|
57
63
|
examples: [
|
|
58
64
|
{
|
|
59
|
-
id:
|
|
65
|
+
id: `${camelTypeName}CreateResponseExample`,
|
|
60
66
|
response: {
|
|
61
67
|
statusCode: HttpStatusCode.created,
|
|
62
68
|
headers: {
|
|
@@ -69,9 +75,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
69
75
|
]
|
|
70
76
|
};
|
|
71
77
|
const blobStorageGetRoute = {
|
|
72
|
-
operationId:
|
|
73
|
-
summary:
|
|
74
|
-
tag: tagsBlobStorage[0].name,
|
|
78
|
+
operationId: `${camelTypeName}Get`,
|
|
79
|
+
summary: `Get the metadata for an item from ${lowerName}`,
|
|
80
|
+
tag: options?.tagName ?? tagsBlobStorage[0].name,
|
|
75
81
|
method: "GET",
|
|
76
82
|
path: `${baseRouteName}/:id`,
|
|
77
83
|
handler: async (httpRequestContext, request) => blobStorageGet(httpRequestContext, componentName, request),
|
|
@@ -79,7 +85,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
79
85
|
type: "IBlobStorageGetRequest",
|
|
80
86
|
examples: [
|
|
81
87
|
{
|
|
82
|
-
id:
|
|
88
|
+
id: `${camelTypeName}GetRequestExample`,
|
|
83
89
|
request: {
|
|
84
90
|
pathParams: {
|
|
85
91
|
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
|
|
@@ -96,7 +102,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
96
102
|
type: "IBlobStorageGetResponse",
|
|
97
103
|
examples: [
|
|
98
104
|
{
|
|
99
|
-
id:
|
|
105
|
+
id: `${camelTypeName}GetResponseExample`,
|
|
100
106
|
response: {
|
|
101
107
|
body: {
|
|
102
108
|
metadata: {
|
|
@@ -116,9 +122,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
116
122
|
]
|
|
117
123
|
};
|
|
118
124
|
const blobStorageGetContentRoute = {
|
|
119
|
-
operationId:
|
|
120
|
-
summary:
|
|
121
|
-
tag: tagsBlobStorage[0].name,
|
|
125
|
+
operationId: `${camelTypeName}GetContent`,
|
|
126
|
+
summary: `Get the content for an item in ${lowerName}`,
|
|
127
|
+
tag: options?.tagName ?? tagsBlobStorage[0].name,
|
|
122
128
|
method: "GET",
|
|
123
129
|
path: `${baseRouteName}/:id/content`,
|
|
124
130
|
handler: async (httpRequestContext, request) => blobStorageGetContent(httpRequestContext, componentName, request),
|
|
@@ -126,7 +132,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
126
132
|
type: "IBlobStorageGetRequest",
|
|
127
133
|
examples: [
|
|
128
134
|
{
|
|
129
|
-
id:
|
|
135
|
+
id: `${camelTypeName}GetContentRequestExample`,
|
|
130
136
|
request: {
|
|
131
137
|
pathParams: {
|
|
132
138
|
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
|
|
@@ -145,7 +151,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
145
151
|
mimeType: MimeTypes.OctetStream,
|
|
146
152
|
examples: [
|
|
147
153
|
{
|
|
148
|
-
id:
|
|
154
|
+
id: `${camelTypeName}GetContentResponseExample`,
|
|
149
155
|
description: `The content of the blob, which will be a specific mime type if one can be detected from the content (or set as mimeType in the metadata), or defaults to ${MimeTypes.OctetStream}.`,
|
|
150
156
|
response: {
|
|
151
157
|
body: new Uint8Array()
|
|
@@ -159,9 +165,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
159
165
|
]
|
|
160
166
|
};
|
|
161
167
|
const blobStorageUpdateRoute = {
|
|
162
|
-
operationId:
|
|
163
|
-
summary:
|
|
164
|
-
tag: tagsBlobStorage[0].name,
|
|
168
|
+
operationId: `${camelTypeName}Update`,
|
|
169
|
+
summary: `Update the metadata for an item in ${lowerName}`,
|
|
170
|
+
tag: options?.tagName ?? tagsBlobStorage[0].name,
|
|
165
171
|
method: "PUT",
|
|
166
172
|
path: `${baseRouteName}/:id`,
|
|
167
173
|
handler: async (httpRequestContext, request) => blobStorageUpdate(httpRequestContext, componentName, request),
|
|
@@ -169,7 +175,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
169
175
|
type: "IBlobStorageUpdateRequest",
|
|
170
176
|
examples: [
|
|
171
177
|
{
|
|
172
|
-
id:
|
|
178
|
+
id: `${camelTypeName}UpdateRequestExample`,
|
|
173
179
|
request: {
|
|
174
180
|
pathParams: {
|
|
175
181
|
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
|
|
@@ -192,9 +198,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
192
198
|
]
|
|
193
199
|
};
|
|
194
200
|
const blobStorageRemoveRoute = {
|
|
195
|
-
operationId:
|
|
196
|
-
summary:
|
|
197
|
-
tag: tagsBlobStorage[0].name,
|
|
201
|
+
operationId: `${camelTypeName}Remove`,
|
|
202
|
+
summary: `Remove an item from ${lowerName}`,
|
|
203
|
+
tag: options?.tagName ?? tagsBlobStorage[0].name,
|
|
198
204
|
method: "DELETE",
|
|
199
205
|
path: `${baseRouteName}/:id`,
|
|
200
206
|
handler: async (httpRequestContext, request) => blobStorageRemove(httpRequestContext, componentName, request),
|
|
@@ -202,7 +208,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
|
|
|
202
208
|
type: "IBlobStorageRemoveRequest",
|
|
203
209
|
examples: [
|
|
204
210
|
{
|
|
205
|
-
id:
|
|
211
|
+
id: `${camelTypeName}RemoveRequestExample`,
|
|
206
212
|
request: {
|
|
207
213
|
pathParams: {
|
|
208
214
|
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
|
|
@@ -260,7 +266,7 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
|
|
|
260
266
|
Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
261
267
|
Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
262
268
|
const component = ComponentFactory.get(componentName);
|
|
263
|
-
const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.nodeIdentity);
|
|
269
|
+
const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
264
270
|
return {
|
|
265
271
|
body: result
|
|
266
272
|
};
|
|
@@ -277,7 +283,7 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
|
|
|
277
283
|
Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
278
284
|
Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
279
285
|
const component = ComponentFactory.get(componentName);
|
|
280
|
-
const result = await component.get(request.pathParams.id, true, httpRequestContext.nodeIdentity);
|
|
286
|
+
const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
281
287
|
const mimeType = result?.mimeType ?? MimeTypes.OctetStream;
|
|
282
288
|
let filename = request.query?.filename;
|
|
283
289
|
if (!Is.stringValue(filename)) {
|
|
@@ -304,7 +310,7 @@ async function blobStorageUpdate(httpRequestContext, componentName, request) {
|
|
|
304
310
|
Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
305
311
|
Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
306
312
|
const component = ComponentFactory.get(componentName);
|
|
307
|
-
await component.update(request.pathParams.id, request.body.mimeType, request.body.extension, request.body.metadata);
|
|
313
|
+
await component.update(request.pathParams.id, request.body.mimeType, request.body.extension, request.body.metadata, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
308
314
|
return {
|
|
309
315
|
statusCode: HttpStatusCode.noContent
|
|
310
316
|
};
|
|
@@ -321,7 +327,7 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
|
|
|
321
327
|
Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
322
328
|
Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
323
329
|
const component = ComponentFactory.get(componentName);
|
|
324
|
-
await component.remove(request.pathParams.id);
|
|
330
|
+
await component.remove(request.pathParams.id, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
325
331
|
return {
|
|
326
332
|
statusCode: HttpStatusCode.noContent
|
|
327
333
|
};
|
|
@@ -362,6 +368,16 @@ class BlobStorageService {
|
|
|
362
368
|
* @internal
|
|
363
369
|
*/
|
|
364
370
|
_vaultKeyId;
|
|
371
|
+
/**
|
|
372
|
+
* Include the node identity when performing storage operations, defaults to true.
|
|
373
|
+
* @internal
|
|
374
|
+
*/
|
|
375
|
+
_includeNodeIdentity;
|
|
376
|
+
/**
|
|
377
|
+
* Include the user identity when performing storage operations, defaults to true.
|
|
378
|
+
* @internal
|
|
379
|
+
*/
|
|
380
|
+
_includeUserIdentity;
|
|
365
381
|
/**
|
|
366
382
|
* Create a new instance of BlobStorageService.
|
|
367
383
|
* @param options The dependencies for the service.
|
|
@@ -380,6 +396,8 @@ class BlobStorageService {
|
|
|
380
396
|
}
|
|
381
397
|
this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
|
|
382
398
|
this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
|
|
399
|
+
this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
|
|
400
|
+
this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
|
|
383
401
|
}
|
|
384
402
|
/**
|
|
385
403
|
* Create the blob with some metadata.
|
|
@@ -388,12 +406,16 @@ class BlobStorageService {
|
|
|
388
406
|
* @param extension Extension for the blob, will be detected if left undefined.
|
|
389
407
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
390
408
|
* @param namespace The namespace to use for storing, defaults to component configured namespace.
|
|
391
|
-
* @param
|
|
409
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
410
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
392
411
|
* @returns The id of the stored blob in urn format.
|
|
393
412
|
*/
|
|
394
|
-
async create(blob, mimeType, extension, metadata, namespace, nodeIdentity) {
|
|
413
|
+
async create(blob, mimeType, extension, metadata, namespace, userIdentity, nodeIdentity) {
|
|
395
414
|
Guards.stringBase64(this.CLASS_NAME, "blob", blob);
|
|
396
|
-
if (this.
|
|
415
|
+
if (this._includeUserIdentity) {
|
|
416
|
+
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
417
|
+
}
|
|
418
|
+
if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
|
|
397
419
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
398
420
|
}
|
|
399
421
|
try {
|
|
@@ -421,12 +443,23 @@ class BlobStorageService {
|
|
|
421
443
|
}
|
|
422
444
|
// Set the blob in the storage connector, which may now be encrypted
|
|
423
445
|
const blobId = await blobStorageConnector.set(storeBlob);
|
|
424
|
-
|
|
446
|
+
// Now store the metadata in entity storage
|
|
447
|
+
const blobMetadata = {
|
|
425
448
|
id: blobId,
|
|
426
449
|
mimeType,
|
|
427
450
|
extension,
|
|
428
451
|
metadata
|
|
429
|
-
}
|
|
452
|
+
};
|
|
453
|
+
const conditions = [];
|
|
454
|
+
if (this._includeUserIdentity) {
|
|
455
|
+
ObjectHelper.propertySet(blobMetadata, "userIdentity", userIdentity);
|
|
456
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
457
|
+
}
|
|
458
|
+
if (this._includeNodeIdentity) {
|
|
459
|
+
ObjectHelper.propertySet(blobMetadata, "nodeIdentity", nodeIdentity);
|
|
460
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
461
|
+
}
|
|
462
|
+
await this._metadataEntityStorage.set(blobMetadata, conditions);
|
|
430
463
|
return blobId;
|
|
431
464
|
}
|
|
432
465
|
catch (error) {
|
|
@@ -437,18 +470,32 @@ class BlobStorageService {
|
|
|
437
470
|
* Get the blob and metadata.
|
|
438
471
|
* @param id The id of the blob to get in urn format.
|
|
439
472
|
* @param includeContent Include the content, or just get the metadata.
|
|
440
|
-
* @param
|
|
473
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
474
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
441
475
|
* @returns The metadata and data for the blob if it can be found.
|
|
442
476
|
* @throws Not found error if the blob cannot be found.
|
|
443
477
|
*/
|
|
444
|
-
async get(id, includeContent, nodeIdentity) {
|
|
478
|
+
async get(id, includeContent, userIdentity, nodeIdentity) {
|
|
445
479
|
Urn.guard(this.CLASS_NAME, "id", id);
|
|
446
|
-
|
|
480
|
+
const conditions = [];
|
|
481
|
+
if (this._includeUserIdentity) {
|
|
482
|
+
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
483
|
+
conditions.push({
|
|
484
|
+
property: "userIdentity",
|
|
485
|
+
comparison: ComparisonOperator.Equals,
|
|
486
|
+
value: userIdentity
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
if (this._includeNodeIdentity || (Is.notEmpty(this._vaultConnector) && includeContent)) {
|
|
447
490
|
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
491
|
+
conditions.push({
|
|
492
|
+
property: "nodeIdentity",
|
|
493
|
+
comparison: ComparisonOperator.Equals,
|
|
494
|
+
value: nodeIdentity
|
|
495
|
+
});
|
|
448
496
|
}
|
|
449
497
|
try {
|
|
450
|
-
|
|
451
|
-
const blobMetadata = await this._metadataEntityStorage.get(id);
|
|
498
|
+
const blobMetadata = await this.internalGet(id, userIdentity, nodeIdentity);
|
|
452
499
|
let returnBlob;
|
|
453
500
|
if (includeContent) {
|
|
454
501
|
const blobStorageConnector = this.getConnector(id);
|
|
@@ -478,11 +525,19 @@ class BlobStorageService {
|
|
|
478
525
|
* @param mimeType Mime type for the blob, will be detected if left undefined.
|
|
479
526
|
* @param extension Extension for the blob, will be detected if left undefined.
|
|
480
527
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
528
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
529
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
481
530
|
* @returns Nothing.
|
|
482
531
|
* @throws Not found error if the blob cannot be found.
|
|
483
532
|
*/
|
|
484
|
-
async update(id, mimeType, extension, metadata) {
|
|
533
|
+
async update(id, mimeType, extension, metadata, userIdentity, nodeIdentity) {
|
|
485
534
|
Urn.guard(this.CLASS_NAME, "id", id);
|
|
535
|
+
if (this._includeUserIdentity) {
|
|
536
|
+
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
537
|
+
}
|
|
538
|
+
if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
|
|
539
|
+
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
540
|
+
}
|
|
486
541
|
try {
|
|
487
542
|
const blobMetadata = await this._metadataEntityStorage.get(id);
|
|
488
543
|
if (Is.undefined(blobMetadata)) {
|
|
@@ -493,12 +548,23 @@ class BlobStorageService {
|
|
|
493
548
|
await JsonLdHelper.validate(metadata, validationFailures);
|
|
494
549
|
Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
|
|
495
550
|
}
|
|
496
|
-
|
|
551
|
+
// Now store the metadata in entity storage
|
|
552
|
+
const updatedBlobMetadata = {
|
|
497
553
|
id: blobMetadata.id,
|
|
498
554
|
mimeType: mimeType ?? blobMetadata.mimeType,
|
|
499
555
|
extension: extension ?? blobMetadata.extension,
|
|
500
556
|
metadata: metadata ?? blobMetadata.metadata
|
|
501
|
-
}
|
|
557
|
+
};
|
|
558
|
+
const conditions = [];
|
|
559
|
+
if (this._includeUserIdentity) {
|
|
560
|
+
ObjectHelper.propertySet(updatedBlobMetadata, "userIdentity", userIdentity);
|
|
561
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
562
|
+
}
|
|
563
|
+
if (this._includeNodeIdentity) {
|
|
564
|
+
ObjectHelper.propertySet(updatedBlobMetadata, "nodeIdentity", nodeIdentity);
|
|
565
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
566
|
+
}
|
|
567
|
+
await this._metadataEntityStorage.set(updatedBlobMetadata, conditions);
|
|
502
568
|
}
|
|
503
569
|
catch (error) {
|
|
504
570
|
throw new GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
|
|
@@ -507,17 +573,32 @@ class BlobStorageService {
|
|
|
507
573
|
/**
|
|
508
574
|
* Remove the blob.
|
|
509
575
|
* @param id The id of the blob to remove in urn format.
|
|
576
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
577
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
510
578
|
* @returns Nothing.
|
|
511
579
|
*/
|
|
512
|
-
async remove(id) {
|
|
580
|
+
async remove(id, userIdentity, nodeIdentity) {
|
|
513
581
|
Urn.guard(this.CLASS_NAME, "id", id);
|
|
582
|
+
if (this._includeUserIdentity) {
|
|
583
|
+
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
584
|
+
}
|
|
585
|
+
if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
|
|
586
|
+
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
587
|
+
}
|
|
514
588
|
try {
|
|
515
589
|
const blobStorageConnector = this.getConnector(id);
|
|
590
|
+
const conditions = [];
|
|
591
|
+
if (this._includeUserIdentity) {
|
|
592
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
593
|
+
}
|
|
594
|
+
if (this._includeNodeIdentity) {
|
|
595
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
596
|
+
}
|
|
597
|
+
await this._metadataEntityStorage.remove(id, conditions);
|
|
516
598
|
const removed = await blobStorageConnector.remove(id);
|
|
517
599
|
if (!removed) {
|
|
518
600
|
throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
|
|
519
601
|
}
|
|
520
|
-
await this._metadataEntityStorage.remove(id);
|
|
521
602
|
}
|
|
522
603
|
catch (error) {
|
|
523
604
|
throw new GeneralError(this.CLASS_NAME, "removeFailed", undefined, error);
|
|
@@ -539,6 +620,58 @@ class BlobStorageService {
|
|
|
539
620
|
}
|
|
540
621
|
return BlobStorageConnectorFactory.get(idUri.namespaceMethod());
|
|
541
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Get an entity.
|
|
625
|
+
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
626
|
+
* @param secondaryIndex Get the item using a secondary index.
|
|
627
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
628
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
629
|
+
* @returns The object if it can be found or throws.
|
|
630
|
+
* @internal
|
|
631
|
+
*/
|
|
632
|
+
async internalGet(id, userIdentity, nodeIdentity) {
|
|
633
|
+
const conditions = [];
|
|
634
|
+
if (this._includeUserIdentity) {
|
|
635
|
+
Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
636
|
+
conditions.push({
|
|
637
|
+
property: "userIdentity",
|
|
638
|
+
comparison: ComparisonOperator.Equals,
|
|
639
|
+
value: userIdentity
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
if (this._includeNodeIdentity) {
|
|
643
|
+
Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
644
|
+
conditions.push({
|
|
645
|
+
property: "nodeIdentity",
|
|
646
|
+
comparison: ComparisonOperator.Equals,
|
|
647
|
+
value: nodeIdentity
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
let entity;
|
|
651
|
+
if (conditions.length === 0) {
|
|
652
|
+
entity = await this._metadataEntityStorage.get(id);
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
const schema = this._metadataEntityStorage.getSchema();
|
|
656
|
+
const primaryKey = EntitySchemaHelper.getPrimaryKey(schema);
|
|
657
|
+
conditions.unshift({
|
|
658
|
+
property: primaryKey.property,
|
|
659
|
+
comparison: ComparisonOperator.Equals,
|
|
660
|
+
value: id
|
|
661
|
+
});
|
|
662
|
+
const results = await this._metadataEntityStorage.query({
|
|
663
|
+
conditions,
|
|
664
|
+
logicalOperator: LogicalOperator.And
|
|
665
|
+
}, undefined, undefined, undefined, 1);
|
|
666
|
+
entity = results.entities[0];
|
|
667
|
+
}
|
|
668
|
+
if (Is.empty(entity)) {
|
|
669
|
+
throw new NotFoundError(this.CLASS_NAME, "entityNotFound", id);
|
|
670
|
+
}
|
|
671
|
+
ObjectHelper.propertyDelete(entity, "nodeIdentity");
|
|
672
|
+
ObjectHelper.propertyDelete(entity, "userIdentity");
|
|
673
|
+
return entity;
|
|
674
|
+
}
|
|
542
675
|
}
|
|
543
676
|
|
|
544
677
|
/**
|
|
@@ -561,6 +694,14 @@ let BlobMetadata = class BlobMetadata {
|
|
|
561
694
|
* The metadata for the blob as JSON-LD.
|
|
562
695
|
*/
|
|
563
696
|
metadata;
|
|
697
|
+
/**
|
|
698
|
+
* The user identity that created the blob.
|
|
699
|
+
*/
|
|
700
|
+
userIdentity;
|
|
701
|
+
/**
|
|
702
|
+
* The node identity that created the blob.
|
|
703
|
+
*/
|
|
704
|
+
nodeIdentity;
|
|
564
705
|
};
|
|
565
706
|
__decorate([
|
|
566
707
|
property({ type: "string", isPrimary: true }),
|
|
@@ -578,14 +719,27 @@ __decorate([
|
|
|
578
719
|
property({ type: "object", itemTypeRef: "IJsonLdNodeObject" }),
|
|
579
720
|
__metadata("design:type", Object)
|
|
580
721
|
], BlobMetadata.prototype, "metadata", void 0);
|
|
722
|
+
__decorate([
|
|
723
|
+
property({ type: "string" }),
|
|
724
|
+
__metadata("design:type", String)
|
|
725
|
+
], BlobMetadata.prototype, "userIdentity", void 0);
|
|
726
|
+
__decorate([
|
|
727
|
+
property({ type: "string" }),
|
|
728
|
+
__metadata("design:type", String)
|
|
729
|
+
], BlobMetadata.prototype, "nodeIdentity", void 0);
|
|
581
730
|
BlobMetadata = __decorate([
|
|
582
731
|
entity()
|
|
583
732
|
], BlobMetadata);
|
|
584
733
|
|
|
734
|
+
/**
|
|
735
|
+
* These are dummy entry points for the blob storage service.
|
|
736
|
+
* In reality your application would create its own entry points based on the
|
|
737
|
+
* blob types it wants to store, using a custom defaultBaseRoute.
|
|
738
|
+
*/
|
|
585
739
|
const restEntryPoints = [
|
|
586
740
|
{
|
|
587
|
-
name: "
|
|
588
|
-
defaultBaseRoute: "blob",
|
|
741
|
+
name: "blob-storage",
|
|
742
|
+
defaultBaseRoute: "blob-storage",
|
|
589
743
|
tags: tagsBlobStorage,
|
|
590
744
|
generateRoutes: generateRestRoutesBlobStorage
|
|
591
745
|
}
|
|
@@ -8,9 +8,15 @@ export declare const tagsBlobStorage: ITag[];
|
|
|
8
8
|
* The REST routes for blob storage.
|
|
9
9
|
* @param baseRouteName Prefix to prepend to the paths.
|
|
10
10
|
* @param componentName The name of the component to use in the routes stored in the ComponentFactory.
|
|
11
|
+
* @param options Additional options for the routes.
|
|
12
|
+
* @param options.typeName Optional type name to use in the routes, defaults to Blob Storage.
|
|
13
|
+
* @param options.tagName Optional name to use in OpenAPI spec for tag.
|
|
11
14
|
* @returns The generated routes.
|
|
12
15
|
*/
|
|
13
|
-
export declare function generateRestRoutesBlobStorage(baseRouteName: string, componentName: string
|
|
16
|
+
export declare function generateRestRoutesBlobStorage(baseRouteName: string, componentName: string, options?: {
|
|
17
|
+
typeName?: string;
|
|
18
|
+
tagName?: string;
|
|
19
|
+
}): IRestRoute[];
|
|
14
20
|
/**
|
|
15
21
|
* Create a blob in storage.
|
|
16
22
|
* @param httpRequestContext The request context for the API.
|
|
@@ -32,19 +32,21 @@ export declare class BlobStorageService implements IBlobStorageComponent {
|
|
|
32
32
|
* @param extension Extension for the blob, will be detected if left undefined.
|
|
33
33
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
34
34
|
* @param namespace The namespace to use for storing, defaults to component configured namespace.
|
|
35
|
-
* @param
|
|
35
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
36
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
36
37
|
* @returns The id of the stored blob in urn format.
|
|
37
38
|
*/
|
|
38
|
-
create(blob: string, mimeType?: string, extension?: string, metadata?: IJsonLdNodeObject, namespace?: string, nodeIdentity?: string): Promise<string>;
|
|
39
|
+
create(blob: string, mimeType?: string, extension?: string, metadata?: IJsonLdNodeObject, namespace?: string, userIdentity?: string, nodeIdentity?: string): Promise<string>;
|
|
39
40
|
/**
|
|
40
41
|
* Get the blob and metadata.
|
|
41
42
|
* @param id The id of the blob to get in urn format.
|
|
42
43
|
* @param includeContent Include the content, or just get the metadata.
|
|
43
|
-
* @param
|
|
44
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
45
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
44
46
|
* @returns The metadata and data for the blob if it can be found.
|
|
45
47
|
* @throws Not found error if the blob cannot be found.
|
|
46
48
|
*/
|
|
47
|
-
get(id: string, includeContent: boolean, nodeIdentity?: string): Promise<{
|
|
49
|
+
get(id: string, includeContent: boolean, userIdentity?: string, nodeIdentity?: string): Promise<{
|
|
48
50
|
blob?: string;
|
|
49
51
|
mimeType?: string;
|
|
50
52
|
extension?: string;
|
|
@@ -56,14 +58,18 @@ export declare class BlobStorageService implements IBlobStorageComponent {
|
|
|
56
58
|
* @param mimeType Mime type for the blob, will be detected if left undefined.
|
|
57
59
|
* @param extension Extension for the blob, will be detected if left undefined.
|
|
58
60
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
61
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
62
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
59
63
|
* @returns Nothing.
|
|
60
64
|
* @throws Not found error if the blob cannot be found.
|
|
61
65
|
*/
|
|
62
|
-
update(id: string, mimeType?: string, extension?: string, metadata?: IJsonLdNodeObject): Promise<void>;
|
|
66
|
+
update(id: string, mimeType?: string, extension?: string, metadata?: IJsonLdNodeObject, userIdentity?: string, nodeIdentity?: string): Promise<void>;
|
|
63
67
|
/**
|
|
64
68
|
* Remove the blob.
|
|
65
69
|
* @param id The id of the blob to remove in urn format.
|
|
70
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
71
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
66
72
|
* @returns Nothing.
|
|
67
73
|
*/
|
|
68
|
-
remove(id: string): Promise<void>;
|
|
74
|
+
remove(id: string, userIdentity?: string, nodeIdentity?: string): Promise<void>;
|
|
69
75
|
}
|
|
@@ -19,4 +19,12 @@ export declare class BlobMetadata {
|
|
|
19
19
|
* The metadata for the blob as JSON-LD.
|
|
20
20
|
*/
|
|
21
21
|
metadata?: IJsonLdNodeObject;
|
|
22
|
+
/**
|
|
23
|
+
* The user identity that created the blob.
|
|
24
|
+
*/
|
|
25
|
+
userIdentity?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The node identity that created the blob.
|
|
28
|
+
*/
|
|
29
|
+
nodeIdentity?: string;
|
|
22
30
|
}
|
|
@@ -12,4 +12,12 @@ export interface IBlobStorageServiceConfig {
|
|
|
12
12
|
* Defaults to the first entry in the factory if not provided.
|
|
13
13
|
*/
|
|
14
14
|
defaultNamespace?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Include the node identity when performing storage operations, defaults to true.
|
|
17
|
+
*/
|
|
18
|
+
includeNodeIdentity?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Include the user identity when performing storage operations, defaults to true.
|
|
21
|
+
*/
|
|
22
|
+
includeUserIdentity?: boolean;
|
|
15
23
|
}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import type { IRestRouteEntryPoint } from "@twin.org/api-models";
|
|
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
|
+
*/
|
|
2
7
|
export declare const restEntryPoints: IRestRouteEntryPoint[];
|
package/docs/changelog.md
CHANGED