@twin.org/blob-storage-service 0.0.1-next.3 → 0.0.1-next.30

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,11 +1,16 @@
1
- import { Guards, ComponentFactory, Is, Converter, GeneralError, Validation, Urn, NotFoundError } from '@twin.org/core';
1
+ import { HttpParameterHelper } from '@twin.org/api-models';
2
+ import { BlobStorageTypes, BlobStorageContexts, BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
3
+ import { StringHelper, Guards, ComponentFactory, Is, Converter, Coerce, GeneralError, Validation, ObjectHelper, Urn, NotFoundError } from '@twin.org/core';
4
+ import { SchemaOrgContexts, SchemaOrgDataTypes } from '@twin.org/standards-schema-org';
2
5
  import { HttpStatusCode, HeaderTypes, MimeTypes, MimeTypeHelper } from '@twin.org/web';
3
- import { BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
4
- import { JsonLdHelper } from '@twin.org/data-json-ld';
6
+ import { Sha256 } from '@twin.org/crypto';
7
+ import { JsonLdHelper, JsonLdProcessor } from '@twin.org/data-json-ld';
8
+ import { ComparisonOperator, LogicalOperator, SortDirection, EntitySchemaHelper, property, entity, EntitySchemaFactory } from '@twin.org/entity';
5
9
  import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
6
10
  import { VaultConnectorFactory, VaultEncryptionType } from '@twin.org/vault-models';
7
- import { property, entity, EntitySchemaFactory, EntitySchemaHelper } from '@twin.org/entity';
8
11
 
12
+ // Copyright 2024 IOTA Stiftung.
13
+ // SPDX-License-Identifier: Apache-2.0.
9
14
  /**
10
15
  * The source used when communicating about these routes.
11
16
  */
@@ -23,13 +28,19 @@ const tagsBlobStorage = [
23
28
  * The REST routes for blob storage.
24
29
  * @param baseRouteName Prefix to prepend to the paths.
25
30
  * @param componentName The name of the component to use in the routes stored in the ComponentFactory.
31
+ * @param options Additional options for the routes.
32
+ * @param options.typeName Optional type name to use in the routes, defaults to Blob Storage.
33
+ * @param options.tagName Optional name to use in OpenAPI spec for tag.
26
34
  * @returns The generated routes.
27
35
  */
28
- function generateRestRoutesBlobStorage(baseRouteName, componentName) {
36
+ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
37
+ const typeName = options?.typeName ?? "Blob Storage";
38
+ const lowerName = typeName.toLowerCase();
39
+ const camelTypeName = StringHelper.camelCase(typeName);
29
40
  const blobStorageCreateRoute = {
30
- operationId: "blobStorageCreate",
31
- summary: "Create a blob in to storage",
32
- tag: tagsBlobStorage[0].name,
41
+ operationId: `${camelTypeName}Create`,
42
+ summary: `Create an entry in ${lowerName}`,
43
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
33
44
  method: "POST",
34
45
  path: `${baseRouteName}/`,
35
46
  handler: async (httpRequestContext, request) => blobStorageCreate(httpRequestContext, componentName, request),
@@ -37,12 +48,12 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
37
48
  type: "IBlobStorageCreateRequest",
38
49
  examples: [
39
50
  {
40
- id: "blobStorageCreateExample",
51
+ id: `${camelTypeName}CreateRequestExample`,
41
52
  request: {
42
53
  body: {
43
54
  blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==",
44
55
  metadata: {
45
- "@context": "http://schema.org/",
56
+ "@context": "https://schema.org",
46
57
  "@type": "DigitalDocument",
47
58
  name: "myfile.pdf"
48
59
  }
@@ -56,7 +67,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
56
67
  type: "ICreatedResponse",
57
68
  examples: [
58
69
  {
59
- id: "blobStorageCreateResponseExample",
70
+ id: `${camelTypeName}CreateResponseExample`,
60
71
  response: {
61
72
  statusCode: HttpStatusCode.created,
62
73
  headers: {
@@ -69,9 +80,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
69
80
  ]
70
81
  };
71
82
  const blobStorageGetRoute = {
72
- operationId: "blobStorageGet",
73
- summary: "Get the blob metadata from storage",
74
- tag: tagsBlobStorage[0].name,
83
+ operationId: `${camelTypeName}Get`,
84
+ summary: `Get the metadata for an item from ${lowerName}`,
85
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
75
86
  method: "GET",
76
87
  path: `${baseRouteName}/:id`,
77
88
  handler: async (httpRequestContext, request) => blobStorageGet(httpRequestContext, componentName, request),
@@ -79,7 +90,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
79
90
  type: "IBlobStorageGetRequest",
80
91
  examples: [
81
92
  {
82
- id: "blobStorageGetRequestExample",
93
+ id: `${camelTypeName}GetRequestExample`,
83
94
  request: {
84
95
  pathParams: {
85
96
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
@@ -96,11 +107,54 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
96
107
  type: "IBlobStorageGetResponse",
97
108
  examples: [
98
109
  {
99
- id: "blobStorageGetResponseExample",
110
+ id: `${camelTypeName}GetResponseExample`,
100
111
  response: {
101
112
  body: {
113
+ "@context": [
114
+ BlobStorageContexts.ContextRoot,
115
+ BlobStorageContexts.ContextRootCommon,
116
+ SchemaOrgContexts.ContextRoot
117
+ ],
118
+ type: BlobStorageTypes.Entry,
119
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
120
+ dateCreated: "2024-01-01T00:00:00Z",
121
+ encodingFormat: MimeTypes.Pdf,
122
+ blobSize: 42,
123
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
124
+ fileExtension: "pdf",
102
125
  metadata: {
103
- "@context": "http://schema.org/",
126
+ "@context": "https://schema.org",
127
+ "@type": "DigitalDocument",
128
+ name: "myfile.pdf"
129
+ },
130
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
131
+ }
132
+ }
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ type: "IBlobStorageGetResponse",
138
+ mimeType: MimeTypes.JsonLd,
139
+ examples: [
140
+ {
141
+ id: `${camelTypeName}GetResponseJsonLdExample`,
142
+ response: {
143
+ body: {
144
+ "@context": [
145
+ BlobStorageContexts.ContextRoot,
146
+ BlobStorageContexts.ContextRootCommon,
147
+ SchemaOrgContexts.ContextRoot
148
+ ],
149
+ type: BlobStorageTypes.Entry,
150
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
151
+ dateCreated: "2024-01-01T00:00:00Z",
152
+ encodingFormat: MimeTypes.Pdf,
153
+ blobSize: 42,
154
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
155
+ fileExtension: "pdf",
156
+ metadata: {
157
+ "@context": "https://schema.org",
104
158
  "@type": "DigitalDocument",
105
159
  name: "myfile.pdf"
106
160
  },
@@ -116,9 +170,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
116
170
  ]
117
171
  };
118
172
  const blobStorageGetContentRoute = {
119
- operationId: "blobStorageGetContent",
120
- summary: "Get the blob from storage",
121
- tag: tagsBlobStorage[0].name,
173
+ operationId: `${camelTypeName}GetContent`,
174
+ summary: `Get the content for an item in ${lowerName}`,
175
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
122
176
  method: "GET",
123
177
  path: `${baseRouteName}/:id/content`,
124
178
  handler: async (httpRequestContext, request) => blobStorageGetContent(httpRequestContext, componentName, request),
@@ -126,7 +180,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
126
180
  type: "IBlobStorageGetRequest",
127
181
  examples: [
128
182
  {
129
- id: "blobStorageGetContentRequestExample",
183
+ id: `${camelTypeName}GetContentRequestExample`,
130
184
  request: {
131
185
  pathParams: {
132
186
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
@@ -145,8 +199,8 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
145
199
  mimeType: MimeTypes.OctetStream,
146
200
  examples: [
147
201
  {
148
- id: "blobStorageGetContentResponseExample",
149
- 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}.`,
202
+ id: `${camelTypeName}GetContentResponseExample`,
203
+ description: `The content of the blob, which will be a specific mime type if one can be detected from the content (or set as encodingFormat in the entry), or defaults to ${MimeTypes.OctetStream}.`,
150
204
  response: {
151
205
  body: new Uint8Array()
152
206
  }
@@ -159,9 +213,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
159
213
  ]
160
214
  };
161
215
  const blobStorageUpdateRoute = {
162
- operationId: "blobStorageUpdate",
163
- summary: "Update a blob metadata in storage",
164
- tag: tagsBlobStorage[0].name,
216
+ operationId: `${camelTypeName}Update`,
217
+ summary: `Update the metadata for an item in ${lowerName}`,
218
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
165
219
  method: "PUT",
166
220
  path: `${baseRouteName}/:id`,
167
221
  handler: async (httpRequestContext, request) => blobStorageUpdate(httpRequestContext, componentName, request),
@@ -169,14 +223,14 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
169
223
  type: "IBlobStorageUpdateRequest",
170
224
  examples: [
171
225
  {
172
- id: "blobStorageUpdateExample",
226
+ id: `${camelTypeName}UpdateRequestExample`,
173
227
  request: {
174
228
  pathParams: {
175
229
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
176
230
  },
177
231
  body: {
178
232
  metadata: {
179
- "@context": "http://schema.org/",
233
+ "@context": "https://schema.org",
180
234
  "@type": "DigitalDocument",
181
235
  name: "myfile.pdf"
182
236
  }
@@ -192,9 +246,9 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
192
246
  ]
193
247
  };
194
248
  const blobStorageRemoveRoute = {
195
- operationId: "blobStorageRemove",
196
- summary: "Remove the blob from storage",
197
- tag: tagsBlobStorage[0].name,
249
+ operationId: `${camelTypeName}Remove`,
250
+ summary: `Remove an item from ${lowerName}`,
251
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
198
252
  method: "DELETE",
199
253
  path: `${baseRouteName}/:id`,
200
254
  handler: async (httpRequestContext, request) => blobStorageRemove(httpRequestContext, componentName, request),
@@ -202,7 +256,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
202
256
  type: "IBlobStorageRemoveRequest",
203
257
  examples: [
204
258
  {
205
- id: "blobStorageRemoveRequestExample",
259
+ id: `${camelTypeName}RemoveRequestExample`,
206
260
  request: {
207
261
  pathParams: {
208
262
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
@@ -220,12 +274,114 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName) {
220
274
  }
221
275
  ]
222
276
  };
277
+ const blobStorageListRoute = {
278
+ operationId: `${camelTypeName}Get`,
279
+ summary: `Query the items from ${lowerName}`,
280
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
281
+ method: "GET",
282
+ path: `${baseRouteName}/`,
283
+ handler: async (httpRequestContext, request) => blobStorageList(httpRequestContext, componentName, request),
284
+ requestType: {
285
+ type: "IBlobStorageListRequest",
286
+ examples: [
287
+ {
288
+ id: `${camelTypeName}ListRequestExample`,
289
+ request: {}
290
+ }
291
+ ]
292
+ },
293
+ responseType: [
294
+ {
295
+ type: "IBlobStorageListResponse",
296
+ examples: [
297
+ {
298
+ id: `${camelTypeName}ListResponseExample`,
299
+ response: {
300
+ body: {
301
+ "@context": [
302
+ BlobStorageContexts.ContextRoot,
303
+ BlobStorageContexts.ContextRootCommon
304
+ ],
305
+ type: BlobStorageTypes.EntryList,
306
+ entries: [
307
+ {
308
+ "@context": [
309
+ BlobStorageContexts.ContextRoot,
310
+ BlobStorageContexts.ContextRootCommon,
311
+ SchemaOrgContexts.ContextRoot
312
+ ],
313
+ type: BlobStorageTypes.Entry,
314
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
315
+ dateCreated: "2024-01-01T00:00:00Z",
316
+ encodingFormat: MimeTypes.Pdf,
317
+ blobSize: 42,
318
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
319
+ fileExtension: "pdf",
320
+ metadata: {
321
+ "@context": "https://schema.org",
322
+ "@type": "DigitalDocument",
323
+ name: "myfile.pdf"
324
+ },
325
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
326
+ }
327
+ ]
328
+ }
329
+ }
330
+ }
331
+ ]
332
+ },
333
+ {
334
+ type: "IBlobStorageListResponse",
335
+ mimeType: MimeTypes.JsonLd,
336
+ examples: [
337
+ {
338
+ id: `${camelTypeName}ListResponseJsonLdExample`,
339
+ response: {
340
+ body: {
341
+ "@context": [
342
+ BlobStorageContexts.ContextRoot,
343
+ BlobStorageContexts.ContextRootCommon
344
+ ],
345
+ type: BlobStorageTypes.EntryList,
346
+ entries: [
347
+ {
348
+ "@context": [
349
+ BlobStorageContexts.ContextRoot,
350
+ BlobStorageContexts.ContextRootCommon,
351
+ SchemaOrgContexts.ContextRoot
352
+ ],
353
+ type: BlobStorageTypes.Entry,
354
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
355
+ dateCreated: "2024-01-01T00:00:00Z",
356
+ encodingFormat: MimeTypes.Pdf,
357
+ blobSize: 42,
358
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
359
+ fileExtension: "pdf",
360
+ metadata: {
361
+ "@context": "https://schema.org",
362
+ "@type": "DigitalDocument",
363
+ name: "myfile.pdf"
364
+ },
365
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
366
+ }
367
+ ]
368
+ }
369
+ }
370
+ }
371
+ ]
372
+ },
373
+ {
374
+ type: "INotFoundResponse"
375
+ }
376
+ ]
377
+ };
223
378
  return [
224
379
  blobStorageCreateRoute,
225
380
  blobStorageGetRoute,
226
381
  blobStorageGetContentRoute,
227
382
  blobStorageUpdateRoute,
228
- blobStorageRemoveRoute
383
+ blobStorageRemoveRoute,
384
+ blobStorageListRoute
229
385
  ];
230
386
  }
231
387
  /**
@@ -240,11 +396,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
240
396
  Guards.object(ROUTES_SOURCE, "request.body", request.body);
241
397
  Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
242
398
  const component = ComponentFactory.get(componentName);
243
- const id = await component.create(request.body.blob, request.body.mimeType, request.body.extension, request.body.metadata, request.body.namespace, httpRequestContext.nodeIdentity);
399
+ const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, request.body.namespace, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
244
400
  return {
245
401
  statusCode: HttpStatusCode.created,
246
402
  headers: {
247
- Location: id
403
+ location: id
248
404
  }
249
405
  };
250
406
  }
@@ -259,9 +415,13 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
259
415
  Guards.object(ROUTES_SOURCE, "request", request);
260
416
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
261
417
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
418
+ const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
262
419
  const component = ComponentFactory.get(componentName);
263
- const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.nodeIdentity);
420
+ const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
264
421
  return {
422
+ headers: {
423
+ [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
424
+ },
265
425
  body: result
266
426
  };
267
427
  }
@@ -277,16 +437,16 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
277
437
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
278
438
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
279
439
  const component = ComponentFactory.get(componentName);
280
- const result = await component.get(request.pathParams.id, true, httpRequestContext.nodeIdentity);
281
- const mimeType = result?.mimeType ?? MimeTypes.OctetStream;
440
+ const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
441
+ const encodingFormat = result?.encodingFormat ?? MimeTypes.OctetStream;
282
442
  let filename = request.query?.filename;
283
443
  if (!Is.stringValue(filename)) {
284
- filename = `file.${result.extension ?? MimeTypeHelper.defaultExtension(mimeType)}`;
444
+ filename = `file.${result.fileExtension ?? MimeTypeHelper.defaultExtension(encodingFormat)}`;
285
445
  }
286
446
  return {
287
447
  body: Is.stringBase64(result.blob) ? Converter.base64ToBytes(result.blob) : new Uint8Array(),
288
448
  attachment: {
289
- mimeType,
449
+ mimeType: encodingFormat,
290
450
  filename,
291
451
  inline: !(request.query?.download ?? false)
292
452
  }
@@ -304,7 +464,7 @@ async function blobStorageUpdate(httpRequestContext, componentName, request) {
304
464
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
305
465
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
306
466
  const component = ComponentFactory.get(componentName);
307
- await component.update(request.pathParams.id, request.body.mimeType, request.body.extension, request.body.metadata);
467
+ await component.update(request.pathParams.id, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
308
468
  return {
309
469
  statusCode: HttpStatusCode.noContent
310
470
  };
@@ -321,11 +481,30 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
321
481
  Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
322
482
  Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
323
483
  const component = ComponentFactory.get(componentName);
324
- await component.remove(request.pathParams.id);
484
+ await component.remove(request.pathParams.id, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
325
485
  return {
326
486
  statusCode: HttpStatusCode.noContent
327
487
  };
328
488
  }
489
+ /**
490
+ * List the entries from blob storage.
491
+ * @param httpRequestContext The request context for the API.
492
+ * @param componentName The name of the component to use in the routes.
493
+ * @param request The request.
494
+ * @returns The response object with additional http response properties.
495
+ */
496
+ async function blobStorageList(httpRequestContext, componentName, request) {
497
+ Guards.object(ROUTES_SOURCE, "request", request);
498
+ const mimeType = request.headers?.[HeaderTypes.Accept] === MimeTypes.JsonLd ? "jsonld" : "json";
499
+ const component = ComponentFactory.get(componentName);
500
+ const result = await component.query(HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, Coerce.number(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
501
+ return {
502
+ headers: {
503
+ [HeaderTypes.ContentType]: mimeType === "json" ? MimeTypes.Json : MimeTypes.JsonLd
504
+ },
505
+ body: result
506
+ };
507
+ }
329
508
 
330
509
  // Copyright 2024 IOTA Stiftung.
331
510
  // SPDX-License-Identifier: Apache-2.0.
@@ -351,7 +530,7 @@ class BlobStorageService {
351
530
  * The storage connector for the metadata.
352
531
  * @internal
353
532
  */
354
- _metadataEntityStorage;
533
+ _entryEntityStorage;
355
534
  /**
356
535
  * The vault connector for the encryption, can be undefined if no encryption required.
357
536
  * @internal
@@ -362,38 +541,52 @@ class BlobStorageService {
362
541
  * @internal
363
542
  */
364
543
  _vaultKeyId;
544
+ /**
545
+ * Include the node identity when performing storage operations, defaults to true.
546
+ * @internal
547
+ */
548
+ _includeNodeIdentity;
549
+ /**
550
+ * Include the user identity when performing storage operations, defaults to true.
551
+ * @internal
552
+ */
553
+ _includeUserIdentity;
365
554
  /**
366
555
  * Create a new instance of BlobStorageService.
367
- * @param options The dependencies for the service.
368
- * @param options.metadataEntityStorageType The type of the storage connector for the metadata, defaults to "blob-metadata".
369
- * @param options.vaultConnectorType The type of the vault connector for encryption, if undefined no encryption will be performed.
370
- * @param options.config The configuration for the service.
556
+ * @param options The options for the service.
371
557
  */
372
558
  constructor(options) {
373
559
  const names = BlobStorageConnectorFactory.names();
374
560
  if (names.length === 0) {
375
561
  throw new GeneralError(this.CLASS_NAME, "noConnectors");
376
562
  }
377
- this._metadataEntityStorage = EntityStorageConnectorFactory.get(options?.metadataEntityStorageType ?? "blob-metadata");
563
+ this._entryEntityStorage = EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
378
564
  if (Is.stringValue(options?.vaultConnectorType)) {
379
565
  this._vaultConnector = VaultConnectorFactory.getIfExists(options.vaultConnectorType);
380
566
  }
381
567
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
382
568
  this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
569
+ this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
570
+ this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
571
+ SchemaOrgDataTypes.registerRedirects();
383
572
  }
384
573
  /**
385
574
  * Create the blob with some metadata.
386
575
  * @param blob The data for the blob in base64 format.
387
- * @param mimeType Mime type for the blob, will be detected if left undefined.
388
- * @param extension Extension for the blob, will be detected if left undefined.
576
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
577
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
389
578
  * @param metadata Data for the custom metadata as JSON-LD.
390
579
  * @param namespace The namespace to use for storing, defaults to component configured namespace.
391
- * @param nodeIdentity The node identity which controls the vault key.
580
+ * @param userIdentity The user identity to use with storage operations.
581
+ * @param nodeIdentity The node identity to use with storage operations.
392
582
  * @returns The id of the stored blob in urn format.
393
583
  */
394
- async create(blob, mimeType, extension, metadata, namespace, nodeIdentity) {
584
+ async create(blob, encodingFormat, fileExtension, metadata, namespace, userIdentity, nodeIdentity) {
395
585
  Guards.stringBase64(this.CLASS_NAME, "blob", blob);
396
- if (this._vaultConnector) {
586
+ if (this._includeUserIdentity) {
587
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
588
+ }
589
+ if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
397
590
  Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
398
591
  }
399
592
  try {
@@ -401,32 +594,48 @@ class BlobStorageService {
401
594
  const blobStorageConnector = BlobStorageConnectorFactory.get(connectorNamespace);
402
595
  // Convert the base64 data into bytes
403
596
  let storeBlob = Converter.base64ToBytes(blob);
597
+ const blobSize = storeBlob.length;
404
598
  // See if we can detect the mime type and default extension for the data.
405
599
  // If not already supplied by the caller. We have to perform this operation
406
600
  // on the unencrypted data.
407
- if (!Is.stringValue(mimeType)) {
408
- mimeType = await MimeTypeHelper.detect(storeBlob);
601
+ if (!Is.stringValue(encodingFormat)) {
602
+ encodingFormat = await MimeTypeHelper.detect(storeBlob);
409
603
  }
410
- if (!Is.stringValue(extension) && Is.stringValue(mimeType)) {
411
- extension = await MimeTypeHelper.defaultExtension(mimeType);
604
+ if (!Is.stringValue(fileExtension) && Is.stringValue(encodingFormat)) {
605
+ fileExtension = await MimeTypeHelper.defaultExtension(encodingFormat);
412
606
  }
413
607
  if (Is.object(metadata)) {
414
608
  const validationFailures = [];
415
609
  JsonLdHelper.validate(metadata, validationFailures);
416
610
  Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
417
611
  }
612
+ const blobHash = `sha256:${Converter.bytesToBase64(Sha256.sum256(storeBlob))}`;
418
613
  // If we have a vault connector then encrypt the data.
419
614
  if (this._vaultConnector) {
420
615
  storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, storeBlob);
421
616
  }
422
617
  // Set the blob in the storage connector, which may now be encrypted
423
618
  const blobId = await blobStorageConnector.set(storeBlob);
424
- await this._metadataEntityStorage.set({
619
+ // Now store the entry in entity storage
620
+ const blobEntry = {
425
621
  id: blobId,
426
- mimeType,
427
- extension,
622
+ dateCreated: new Date(Date.now()).toISOString(),
623
+ blobSize,
624
+ blobHash,
625
+ encodingFormat,
626
+ fileExtension,
428
627
  metadata
429
- });
628
+ };
629
+ const conditions = [];
630
+ if (this._includeUserIdentity) {
631
+ ObjectHelper.propertySet(blobEntry, "userIdentity", userIdentity);
632
+ conditions.push({ property: "userIdentity", value: userIdentity });
633
+ }
634
+ if (this._includeNodeIdentity) {
635
+ ObjectHelper.propertySet(blobEntry, "nodeIdentity", nodeIdentity);
636
+ conditions.push({ property: "nodeIdentity", value: nodeIdentity });
637
+ }
638
+ await this._entryEntityStorage.set(blobEntry, conditions);
430
639
  return blobId;
431
640
  }
432
641
  catch (error) {
@@ -434,21 +643,35 @@ class BlobStorageService {
434
643
  }
435
644
  }
436
645
  /**
437
- * Get the blob and metadata.
646
+ * Get the blob entry.
438
647
  * @param id The id of the blob to get in urn format.
439
648
  * @param includeContent Include the content, or just get the metadata.
440
- * @param nodeIdentity The node identity which controls the vault key.
441
- * @returns The metadata and data for the blob if it can be found.
649
+ * @param userIdentity The user identity to use with storage operations.
650
+ * @param nodeIdentity The node identity to use with storage operations.
651
+ * @returns The entry and data for the blob if it can be found.
442
652
  * @throws Not found error if the blob cannot be found.
443
653
  */
444
- async get(id, includeContent, nodeIdentity) {
654
+ async get(id, includeContent, userIdentity, nodeIdentity) {
445
655
  Urn.guard(this.CLASS_NAME, "id", id);
446
- if (this._vaultConnector && includeContent) {
656
+ const conditions = [];
657
+ if (this._includeUserIdentity) {
658
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
659
+ conditions.push({
660
+ property: "userIdentity",
661
+ comparison: ComparisonOperator.Equals,
662
+ value: userIdentity
663
+ });
664
+ }
665
+ if (this._includeNodeIdentity || (Is.notEmpty(this._vaultConnector) && includeContent)) {
447
666
  Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
667
+ conditions.push({
668
+ property: "nodeIdentity",
669
+ comparison: ComparisonOperator.Equals,
670
+ value: nodeIdentity
671
+ });
448
672
  }
449
673
  try {
450
- // Get the metadata
451
- const blobMetadata = await this._metadataEntityStorage.get(id);
674
+ const blobEntry = await this.internalGet(id, userIdentity, nodeIdentity);
452
675
  let returnBlob;
453
676
  if (includeContent) {
454
677
  const blobStorageConnector = this.getConnector(id);
@@ -461,12 +684,8 @@ class BlobStorageService {
461
684
  returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, VaultEncryptionType.ChaCha20Poly1305, returnBlob);
462
685
  }
463
686
  }
464
- return {
465
- blob: Is.uint8Array(returnBlob) ? Converter.bytesToBase64(returnBlob) : undefined,
466
- mimeType: blobMetadata?.mimeType,
467
- extension: blobMetadata?.extension,
468
- metadata: blobMetadata?.metadata
469
- };
687
+ const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
688
+ return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
470
689
  }
471
690
  catch (error) {
472
691
  throw new GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
@@ -474,18 +693,26 @@ class BlobStorageService {
474
693
  }
475
694
  /**
476
695
  * Update the blob with metadata.
477
- * @param id The id of the blob metadata to update.
478
- * @param mimeType Mime type for the blob, will be detected if left undefined.
479
- * @param extension Extension for the blob, will be detected if left undefined.
696
+ * @param id The id of the blob entry to update.
697
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
698
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
480
699
  * @param metadata Data for the custom metadata as JSON-LD.
700
+ * @param userIdentity The user identity to use with storage operations.
701
+ * @param nodeIdentity The node identity to use with storage operations.
481
702
  * @returns Nothing.
482
703
  * @throws Not found error if the blob cannot be found.
483
704
  */
484
- async update(id, mimeType, extension, metadata) {
705
+ async update(id, encodingFormat, fileExtension, metadata, userIdentity, nodeIdentity) {
485
706
  Urn.guard(this.CLASS_NAME, "id", id);
707
+ if (this._includeUserIdentity) {
708
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
709
+ }
710
+ if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
711
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
712
+ }
486
713
  try {
487
- const blobMetadata = await this._metadataEntityStorage.get(id);
488
- if (Is.undefined(blobMetadata)) {
714
+ const blobEntry = await this._entryEntityStorage.get(id);
715
+ if (Is.undefined(blobEntry)) {
489
716
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
490
717
  }
491
718
  if (Is.object(metadata)) {
@@ -493,12 +720,27 @@ class BlobStorageService {
493
720
  await JsonLdHelper.validate(metadata, validationFailures);
494
721
  Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
495
722
  }
496
- await this._metadataEntityStorage.set({
497
- id: blobMetadata.id,
498
- mimeType: mimeType ?? blobMetadata.mimeType,
499
- extension: extension ?? blobMetadata.extension,
500
- metadata: metadata ?? blobMetadata.metadata
501
- });
723
+ // Now store the entry in entity storage
724
+ const updatedBlobEntry = {
725
+ id: blobEntry.id,
726
+ dateCreated: blobEntry.dateCreated,
727
+ dateModified: new Date(Date.now()).toISOString(),
728
+ blobSize: blobEntry.blobSize,
729
+ blobHash: blobEntry.blobHash,
730
+ encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
731
+ fileExtension: fileExtension ?? blobEntry.fileExtension,
732
+ metadata: metadata ?? blobEntry.metadata
733
+ };
734
+ const conditions = [];
735
+ if (this._includeUserIdentity) {
736
+ ObjectHelper.propertySet(updatedBlobEntry, "userIdentity", userIdentity);
737
+ conditions.push({ property: "userIdentity", value: userIdentity });
738
+ }
739
+ if (this._includeNodeIdentity) {
740
+ ObjectHelper.propertySet(updatedBlobEntry, "nodeIdentity", nodeIdentity);
741
+ conditions.push({ property: "nodeIdentity", value: nodeIdentity });
742
+ }
743
+ await this._entryEntityStorage.set(updatedBlobEntry, conditions);
502
744
  }
503
745
  catch (error) {
504
746
  throw new GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
@@ -507,22 +749,104 @@ class BlobStorageService {
507
749
  /**
508
750
  * Remove the blob.
509
751
  * @param id The id of the blob to remove in urn format.
752
+ * @param userIdentity The user identity to use with storage operations.
753
+ * @param nodeIdentity The node identity to use with storage operations.
510
754
  * @returns Nothing.
511
755
  */
512
- async remove(id) {
756
+ async remove(id, userIdentity, nodeIdentity) {
513
757
  Urn.guard(this.CLASS_NAME, "id", id);
758
+ if (this._includeUserIdentity) {
759
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
760
+ }
761
+ if (this._includeNodeIdentity || Is.notEmpty(this._vaultConnector)) {
762
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
763
+ }
514
764
  try {
515
765
  const blobStorageConnector = this.getConnector(id);
766
+ const conditions = [];
767
+ if (this._includeUserIdentity) {
768
+ conditions.push({ property: "userIdentity", value: userIdentity });
769
+ }
770
+ if (this._includeNodeIdentity) {
771
+ conditions.push({ property: "nodeIdentity", value: nodeIdentity });
772
+ }
773
+ await this._entryEntityStorage.remove(id, conditions);
516
774
  const removed = await blobStorageConnector.remove(id);
517
775
  if (!removed) {
518
776
  throw new NotFoundError(this.CLASS_NAME, "blobNotFound", id);
519
777
  }
520
- await this._metadataEntityStorage.remove(id);
521
778
  }
522
779
  catch (error) {
523
780
  throw new GeneralError(this.CLASS_NAME, "removeFailed", undefined, error);
524
781
  }
525
782
  }
783
+ /**
784
+ * Query all the blob storage entries which match the conditions.
785
+ * @param conditions The conditions to match for the entries.
786
+ * @param orderBy The order for the results, defaults to created.
787
+ * @param orderByDirection The direction for the order, defaults to descending.
788
+ * @param cursor The cursor to request the next page of entries.
789
+ * @param pageSize The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
790
+ * @param userIdentity The user identity to use with storage operations.
791
+ * @param nodeIdentity The node identity to use with storage operations.
792
+ * @returns All the entries for the storage matching the conditions,
793
+ * and a cursor which can be used to request more entities.
794
+ */
795
+ async query(conditions, orderBy, orderByDirection, cursor, pageSize, userIdentity, nodeIdentity) {
796
+ const finalConditions = {
797
+ conditions: [],
798
+ logicalOperator: LogicalOperator.And
799
+ };
800
+ if (this._includeNodeIdentity) {
801
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
802
+ finalConditions.conditions.push({
803
+ property: "nodeIdentity",
804
+ comparison: ComparisonOperator.Equals,
805
+ value: nodeIdentity
806
+ });
807
+ }
808
+ if (this._includeUserIdentity) {
809
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
810
+ finalConditions.conditions.push({
811
+ property: "userIdentity",
812
+ comparison: ComparisonOperator.Equals,
813
+ value: userIdentity
814
+ });
815
+ }
816
+ if (!Is.empty(conditions)) {
817
+ finalConditions.conditions.push(conditions);
818
+ }
819
+ const orderProperty = orderBy ?? "dateCreated";
820
+ const orderDirection = orderByDirection ?? SortDirection.Descending;
821
+ const result = await this._entryEntityStorage.query(finalConditions.conditions.length > 0 ? finalConditions : undefined, [
822
+ {
823
+ property: orderProperty,
824
+ sortDirection: orderDirection
825
+ }
826
+ ], undefined, cursor, pageSize);
827
+ for (const entity of result.entities) {
828
+ ObjectHelper.propertyDelete(entity, "nodeIdentity");
829
+ ObjectHelper.propertyDelete(entity, "userIdentity");
830
+ }
831
+ let context = [
832
+ BlobStorageContexts.ContextRoot,
833
+ BlobStorageContexts.ContextRootCommon,
834
+ SchemaOrgContexts.ContextRoot
835
+ ];
836
+ const entriesJsonLd = [];
837
+ for (const entry of result.entities) {
838
+ // The entries are never Partial as we don't allow custom property requests.
839
+ entriesJsonLd.push(this.entryToJsonLd(entry));
840
+ context = JsonLdProcessor.combineContexts(context, entry.metadata?.["@context"]);
841
+ }
842
+ const jsonLd = {
843
+ "@context": context,
844
+ type: BlobStorageTypes.EntryList,
845
+ entries: entriesJsonLd,
846
+ cursor: result.cursor
847
+ };
848
+ return JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
849
+ }
526
850
  /**
527
851
  * Get the connector from the uri.
528
852
  * @param id The id of the blob storage item in urn format.
@@ -539,53 +863,190 @@ class BlobStorageService {
539
863
  }
540
864
  return BlobStorageConnectorFactory.get(idUri.namespaceMethod());
541
865
  }
866
+ /**
867
+ * Get an entity.
868
+ * @param id The id of the entity to get, or the index value if secondaryIndex is set.
869
+ * @param secondaryIndex Get the item using a secondary index.
870
+ * @param userIdentity The user identity to use with storage operations.
871
+ * @param nodeIdentity The node identity to use with storage operations.
872
+ * @returns The object if it can be found or throws.
873
+ * @internal
874
+ */
875
+ async internalGet(id, userIdentity, nodeIdentity) {
876
+ const conditions = [];
877
+ if (this._includeUserIdentity) {
878
+ Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
879
+ conditions.push({
880
+ property: "userIdentity",
881
+ comparison: ComparisonOperator.Equals,
882
+ value: userIdentity
883
+ });
884
+ }
885
+ if (this._includeNodeIdentity) {
886
+ Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
887
+ conditions.push({
888
+ property: "nodeIdentity",
889
+ comparison: ComparisonOperator.Equals,
890
+ value: nodeIdentity
891
+ });
892
+ }
893
+ let entity;
894
+ if (conditions.length === 0) {
895
+ entity = await this._entryEntityStorage.get(id);
896
+ }
897
+ else {
898
+ const schema = this._entryEntityStorage.getSchema();
899
+ const primaryKey = EntitySchemaHelper.getPrimaryKey(schema);
900
+ conditions.unshift({
901
+ property: primaryKey.property,
902
+ comparison: ComparisonOperator.Equals,
903
+ value: id
904
+ });
905
+ const results = await this._entryEntityStorage.query({
906
+ conditions,
907
+ logicalOperator: LogicalOperator.And
908
+ }, undefined, undefined, undefined, 1);
909
+ entity = results.entities[0];
910
+ }
911
+ if (Is.empty(entity)) {
912
+ throw new NotFoundError(this.CLASS_NAME, "entityNotFound", id);
913
+ }
914
+ ObjectHelper.propertyDelete(entity, "nodeIdentity");
915
+ ObjectHelper.propertyDelete(entity, "userIdentity");
916
+ return entity;
917
+ }
918
+ /**
919
+ * Convert the entry to JSON-LD.
920
+ * @param entry The entry to convert.
921
+ * @param blob The optional blob to return.
922
+ * @returns The JSON-LD representation of the entry.
923
+ * @internal
924
+ */
925
+ entryToJsonLd(entry, blob) {
926
+ const jsonLd = {
927
+ "@context": JsonLdProcessor.combineContexts([
928
+ BlobStorageContexts.ContextRoot,
929
+ BlobStorageContexts.ContextRootCommon,
930
+ SchemaOrgContexts.ContextRoot
931
+ ], entry?.metadata?.["@context"]),
932
+ id: entry.id,
933
+ type: BlobStorageTypes.Entry,
934
+ dateCreated: entry.dateCreated,
935
+ dateModified: entry.dateModified,
936
+ blobSize: entry.blobSize,
937
+ blobHash: entry.blobHash,
938
+ encodingFormat: entry?.encodingFormat,
939
+ fileExtension: entry?.fileExtension,
940
+ metadata: entry?.metadata,
941
+ blob: Is.uint8Array(blob) ? Converter.bytesToBase64(blob) : undefined
942
+ };
943
+ return jsonLd;
944
+ }
542
945
  }
543
946
 
544
947
  /**
545
- * Class representing metadata for the blob storage.
948
+ * Class representing entry for the blob storage.
546
949
  */
547
- let BlobMetadata = class BlobMetadata {
950
+ let BlobStorageEntry = class BlobStorageEntry {
548
951
  /**
549
952
  * The id for the blob.
550
953
  */
551
954
  id;
955
+ /**
956
+ * The date/time when the entry was created.
957
+ */
958
+ dateCreated;
959
+ /**
960
+ * The date/time when the entry was modified.
961
+ */
962
+ dateModified;
963
+ /**
964
+ * The length of the data in the blob.
965
+ */
966
+ blobSize;
967
+ /**
968
+ * The hash of the data in the blob.
969
+ */
970
+ blobHash;
552
971
  /**
553
972
  * The mime type for the blob.
554
973
  */
555
- mimeType;
974
+ encodingFormat;
556
975
  /**
557
976
  * The extension.
558
977
  */
559
- extension;
978
+ fileExtension;
560
979
  /**
561
980
  * The metadata for the blob as JSON-LD.
562
981
  */
563
982
  metadata;
983
+ /**
984
+ * The user identity that created the blob.
985
+ */
986
+ userIdentity;
987
+ /**
988
+ * The node identity that created the blob.
989
+ */
990
+ nodeIdentity;
564
991
  };
565
992
  __decorate([
566
993
  property({ type: "string", isPrimary: true }),
567
994
  __metadata("design:type", String)
568
- ], BlobMetadata.prototype, "id", void 0);
995
+ ], BlobStorageEntry.prototype, "id", void 0);
569
996
  __decorate([
570
- property({ type: "string" }),
997
+ property({ type: "string", format: "date-time", sortDirection: SortDirection.Descending }),
571
998
  __metadata("design:type", String)
572
- ], BlobMetadata.prototype, "mimeType", void 0);
999
+ ], BlobStorageEntry.prototype, "dateCreated", void 0);
1000
+ __decorate([
1001
+ property({
1002
+ type: "string",
1003
+ format: "date-time",
1004
+ sortDirection: SortDirection.Descending,
1005
+ optional: true
1006
+ }),
1007
+ __metadata("design:type", String)
1008
+ ], BlobStorageEntry.prototype, "dateModified", void 0);
1009
+ __decorate([
1010
+ property({ type: "number" }),
1011
+ __metadata("design:type", Number)
1012
+ ], BlobStorageEntry.prototype, "blobSize", void 0);
573
1013
  __decorate([
574
1014
  property({ type: "string" }),
575
1015
  __metadata("design:type", String)
576
- ], BlobMetadata.prototype, "extension", void 0);
1016
+ ], BlobStorageEntry.prototype, "blobHash", void 0);
1017
+ __decorate([
1018
+ property({ type: "string", optional: true }),
1019
+ __metadata("design:type", String)
1020
+ ], BlobStorageEntry.prototype, "encodingFormat", void 0);
1021
+ __decorate([
1022
+ property({ type: "string", optional: true }),
1023
+ __metadata("design:type", String)
1024
+ ], BlobStorageEntry.prototype, "fileExtension", void 0);
577
1025
  __decorate([
578
- property({ type: "object", itemTypeRef: "IJsonLdNodeObject" }),
1026
+ property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
579
1027
  __metadata("design:type", Object)
580
- ], BlobMetadata.prototype, "metadata", void 0);
581
- BlobMetadata = __decorate([
1028
+ ], BlobStorageEntry.prototype, "metadata", void 0);
1029
+ __decorate([
1030
+ property({ type: "string", optional: true }),
1031
+ __metadata("design:type", String)
1032
+ ], BlobStorageEntry.prototype, "userIdentity", void 0);
1033
+ __decorate([
1034
+ property({ type: "string", optional: true }),
1035
+ __metadata("design:type", String)
1036
+ ], BlobStorageEntry.prototype, "nodeIdentity", void 0);
1037
+ BlobStorageEntry = __decorate([
582
1038
  entity()
583
- ], BlobMetadata);
1039
+ ], BlobStorageEntry);
584
1040
 
1041
+ /**
1042
+ * These are dummy entry points for the blob storage service.
1043
+ * In reality your application would create its own entry points based on the
1044
+ * blob types it wants to store, using a custom defaultBaseRoute.
1045
+ */
585
1046
  const restEntryPoints = [
586
1047
  {
587
- name: "blobStorage",
588
- defaultBaseRoute: "blob",
1048
+ name: "blob-storage",
1049
+ defaultBaseRoute: "blob-storage",
589
1050
  tags: tagsBlobStorage,
590
1051
  generateRoutes: generateRestRoutesBlobStorage
591
1052
  }
@@ -597,7 +1058,7 @@ const restEntryPoints = [
597
1058
  * Initialize the schema for the blob storage entities.
598
1059
  */
599
1060
  function initSchema() {
600
- EntitySchemaFactory.register("BlobMetadata", () => EntitySchemaHelper.getSchema(BlobMetadata));
1061
+ EntitySchemaFactory.register("BlobStorageEntry", () => EntitySchemaHelper.getSchema(BlobStorageEntry));
601
1062
  }
602
1063
 
603
- export { BlobMetadata, BlobStorageService, blobStorageCreate, blobStorageGet, blobStorageGetContent, blobStorageRemove, blobStorageUpdate, generateRestRoutesBlobStorage, initSchema, restEntryPoints, tagsBlobStorage };
1064
+ export { BlobStorageEntry, BlobStorageService, blobStorageCreate, blobStorageGet, blobStorageGetContent, blobStorageList, blobStorageRemove, blobStorageUpdate, generateRestRoutesBlobStorage, initSchema, restEntryPoints, tagsBlobStorage };