@twin.org/blob-storage-service 0.0.1-next.9 → 0.0.2-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,18 @@
1
1
  'use strict';
2
2
 
3
+ var apiModels = require('@twin.org/api-models');
4
+ var blobStorageModels = require('@twin.org/blob-storage-models');
3
5
  var core = require('@twin.org/core');
6
+ var standardsSchemaOrg = require('@twin.org/standards-schema-org');
4
7
  var web = require('@twin.org/web');
5
- var blobStorageModels = require('@twin.org/blob-storage-models');
8
+ var crypto = require('@twin.org/crypto');
6
9
  var dataJsonLd = require('@twin.org/data-json-ld');
7
10
  var entity = require('@twin.org/entity');
8
11
  var entityStorageModels = require('@twin.org/entity-storage-models');
9
12
  var vaultModels = require('@twin.org/vault-models');
10
13
 
14
+ // Copyright 2024 IOTA Stiftung.
15
+ // SPDX-License-Identifier: Apache-2.0.
11
16
  /**
12
17
  * The source used when communicating about these routes.
13
18
  */
@@ -50,7 +55,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
50
55
  body: {
51
56
  blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==",
52
57
  metadata: {
53
- "@context": "http://schema.org/",
58
+ "@context": "https://schema.org",
54
59
  "@type": "DigitalDocument",
55
60
  name: "myfile.pdf"
56
61
  }
@@ -93,7 +98,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
93
98
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
94
99
  },
95
100
  query: {
96
- includeContent: true
101
+ includeContent: "true"
97
102
  }
98
103
  }
99
104
  }
@@ -107,8 +112,51 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
107
112
  id: `${camelTypeName}GetResponseExample`,
108
113
  response: {
109
114
  body: {
115
+ "@context": [
116
+ blobStorageModels.BlobStorageContexts.ContextRoot,
117
+ blobStorageModels.BlobStorageContexts.ContextRootCommon,
118
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot
119
+ ],
120
+ type: blobStorageModels.BlobStorageTypes.Entry,
121
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
122
+ dateCreated: "2024-01-01T00:00:00Z",
123
+ encodingFormat: web.MimeTypes.Pdf,
124
+ blobSize: 42,
125
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
126
+ fileExtension: "pdf",
127
+ metadata: {
128
+ "@context": "https://schema.org",
129
+ "@type": "DigitalDocument",
130
+ name: "myfile.pdf"
131
+ },
132
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
133
+ }
134
+ }
135
+ }
136
+ ]
137
+ },
138
+ {
139
+ type: "IBlobStorageGetResponse",
140
+ mimeType: web.MimeTypes.JsonLd,
141
+ examples: [
142
+ {
143
+ id: `${camelTypeName}GetResponseJsonLdExample`,
144
+ response: {
145
+ body: {
146
+ "@context": [
147
+ blobStorageModels.BlobStorageContexts.ContextRoot,
148
+ blobStorageModels.BlobStorageContexts.ContextRootCommon,
149
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot
150
+ ],
151
+ type: blobStorageModels.BlobStorageTypes.Entry,
152
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
153
+ dateCreated: "2024-01-01T00:00:00Z",
154
+ encodingFormat: web.MimeTypes.Pdf,
155
+ blobSize: 42,
156
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
157
+ fileExtension: "pdf",
110
158
  metadata: {
111
- "@context": "http://schema.org/",
159
+ "@context": "https://schema.org",
112
160
  "@type": "DigitalDocument",
113
161
  name: "myfile.pdf"
114
162
  },
@@ -140,7 +188,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
140
188
  id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70"
141
189
  },
142
190
  query: {
143
- download: true,
191
+ download: "true",
144
192
  filename: "my-file.pdf"
145
193
  }
146
194
  }
@@ -154,7 +202,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
154
202
  examples: [
155
203
  {
156
204
  id: `${camelTypeName}GetContentResponseExample`,
157
- 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 ${web.MimeTypes.OctetStream}.`,
205
+ 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 ${web.MimeTypes.OctetStream}.`,
158
206
  response: {
159
207
  body: new Uint8Array()
160
208
  }
@@ -184,7 +232,7 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
184
232
  },
185
233
  body: {
186
234
  metadata: {
187
- "@context": "http://schema.org/",
235
+ "@context": "https://schema.org",
188
236
  "@type": "DigitalDocument",
189
237
  name: "myfile.pdf"
190
238
  }
@@ -228,12 +276,116 @@ function generateRestRoutesBlobStorage(baseRouteName, componentName, options) {
228
276
  }
229
277
  ]
230
278
  };
279
+ const blobStorageListRoute = {
280
+ operationId: `${camelTypeName}Query`,
281
+ summary: `Query the items from ${lowerName}`,
282
+ tag: options?.tagName ?? tagsBlobStorage[0].name,
283
+ method: "GET",
284
+ path: `${baseRouteName}/`,
285
+ handler: async (httpRequestContext, request) => blobStorageList(httpRequestContext, componentName, request),
286
+ requestType: {
287
+ type: "IBlobStorageListRequest",
288
+ examples: [
289
+ {
290
+ id: `${camelTypeName}ListRequestExample`,
291
+ request: {}
292
+ }
293
+ ]
294
+ },
295
+ responseType: [
296
+ {
297
+ type: "IBlobStorageListResponse",
298
+ examples: [
299
+ {
300
+ id: `${camelTypeName}ListResponseExample`,
301
+ response: {
302
+ body: {
303
+ "@context": [
304
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
305
+ blobStorageModels.BlobStorageContexts.ContextRoot,
306
+ blobStorageModels.BlobStorageContexts.ContextRootCommon
307
+ ],
308
+ type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
309
+ [standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
310
+ {
311
+ "@context": [
312
+ blobStorageModels.BlobStorageContexts.ContextRoot,
313
+ blobStorageModels.BlobStorageContexts.ContextRootCommon,
314
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot
315
+ ],
316
+ type: blobStorageModels.BlobStorageTypes.Entry,
317
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
318
+ dateCreated: "2024-01-01T00:00:00Z",
319
+ encodingFormat: web.MimeTypes.Pdf,
320
+ blobSize: 42,
321
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
322
+ fileExtension: "pdf",
323
+ metadata: {
324
+ "@context": "https://schema.org",
325
+ "@type": "DigitalDocument",
326
+ name: "myfile.pdf"
327
+ },
328
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
329
+ }
330
+ ]
331
+ }
332
+ }
333
+ }
334
+ ]
335
+ },
336
+ {
337
+ type: "IBlobStorageListResponse",
338
+ mimeType: web.MimeTypes.JsonLd,
339
+ examples: [
340
+ {
341
+ id: `${camelTypeName}ListResponseJsonLdExample`,
342
+ response: {
343
+ body: {
344
+ "@context": [
345
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
346
+ blobStorageModels.BlobStorageContexts.ContextRoot,
347
+ blobStorageModels.BlobStorageContexts.ContextRootCommon
348
+ ],
349
+ type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
350
+ [standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
351
+ {
352
+ "@context": [
353
+ blobStorageModels.BlobStorageContexts.ContextRoot,
354
+ blobStorageModels.BlobStorageContexts.ContextRootCommon,
355
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot
356
+ ],
357
+ type: blobStorageModels.BlobStorageTypes.Entry,
358
+ id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
359
+ dateCreated: "2024-01-01T00:00:00Z",
360
+ encodingFormat: web.MimeTypes.Pdf,
361
+ blobSize: 42,
362
+ blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
363
+ fileExtension: "pdf",
364
+ metadata: {
365
+ "@context": "https://schema.org",
366
+ "@type": "DigitalDocument",
367
+ name: "myfile.pdf"
368
+ },
369
+ blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
370
+ }
371
+ ]
372
+ }
373
+ }
374
+ }
375
+ ]
376
+ },
377
+ {
378
+ type: "INotFoundResponse"
379
+ }
380
+ ]
381
+ };
231
382
  return [
232
383
  blobStorageCreateRoute,
233
384
  blobStorageGetRoute,
234
385
  blobStorageGetContentRoute,
235
386
  blobStorageUpdateRoute,
236
- blobStorageRemoveRoute
387
+ blobStorageRemoveRoute,
388
+ blobStorageListRoute
237
389
  ];
238
390
  }
239
391
  /**
@@ -248,7 +400,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
248
400
  core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
249
401
  core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
250
402
  const component = core.ComponentFactory.get(componentName);
251
- const id = await component.create(request.body.blob, request.body.mimeType, request.body.extension, request.body.metadata, request.body.namespace, httpRequestContext.nodeIdentity);
403
+ const id = await component.create(request.body.blob, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, {
404
+ disableEncryption: request.body.disableEncryption,
405
+ overrideVaultKeyId: request.body.overrideVaultKeyId,
406
+ namespace: request.body.namespace
407
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
252
408
  return {
253
409
  statusCode: web.HttpStatusCode.created,
254
410
  headers: {
@@ -267,9 +423,17 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
267
423
  core.Guards.object(ROUTES_SOURCE, "request", request);
268
424
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
269
425
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
426
+ const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
270
427
  const component = core.ComponentFactory.get(componentName);
271
- const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
428
+ const result = await component.get(request.pathParams.id, {
429
+ includeContent: core.Coerce.boolean(request.query?.includeContent),
430
+ decompress: core.Coerce.boolean(request.query?.decompress),
431
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
432
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
272
433
  return {
434
+ headers: {
435
+ [web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
436
+ },
273
437
  body: result
274
438
  };
275
439
  }
@@ -285,18 +449,34 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
285
449
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
286
450
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
287
451
  const component = core.ComponentFactory.get(componentName);
288
- const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
289
- const mimeType = result?.mimeType ?? web.MimeTypes.OctetStream;
452
+ const decompress = core.Coerce.boolean(request.query?.decompress);
453
+ const download = core.Coerce.boolean(request.query?.download) ?? false;
454
+ const result = await component.get(request.pathParams.id, {
455
+ includeContent: true,
456
+ decompress,
457
+ overrideVaultKeyId: request.query?.overrideVaultKeyId
458
+ }, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
459
+ const encodingFormat = result?.encodingFormat ?? web.MimeTypes.OctetStream;
460
+ let compressedEncodingFormat;
461
+ let compressedExtension = "";
462
+ // If the entry is compressed and we are not decompressing
463
+ // we need to override the encoding format to the compressed type
464
+ // and append an additional extension to the filename.
465
+ if (result.compression && !decompress) {
466
+ compressedEncodingFormat =
467
+ result.compression === blobStorageModels.BlobStorageCompressionType.Gzip ? web.MimeTypes.Gzip : web.MimeTypes.Zlib;
468
+ compressedExtension = `.${web.MimeTypeHelper.defaultExtension(compressedEncodingFormat)}`;
469
+ }
290
470
  let filename = request.query?.filename;
291
471
  if (!core.Is.stringValue(filename)) {
292
- filename = `file.${result.extension ?? web.MimeTypeHelper.defaultExtension(mimeType)}`;
472
+ filename = `file.${result.fileExtension ?? web.MimeTypeHelper.defaultExtension(encodingFormat)}${compressedExtension}`;
293
473
  }
294
474
  return {
295
475
  body: core.Is.stringBase64(result.blob) ? core.Converter.base64ToBytes(result.blob) : new Uint8Array(),
296
476
  attachment: {
297
- mimeType,
477
+ mimeType: compressedEncodingFormat ?? encodingFormat,
298
478
  filename,
299
- inline: !(request.query?.download ?? false)
479
+ inline: !download
300
480
  }
301
481
  };
302
482
  }
@@ -312,7 +492,7 @@ async function blobStorageUpdate(httpRequestContext, componentName, request) {
312
492
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
313
493
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
314
494
  const component = core.ComponentFactory.get(componentName);
315
- await component.update(request.pathParams.id, request.body.mimeType, request.body.extension, request.body.metadata, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
495
+ await component.update(request.pathParams.id, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, httpRequestContext.userIdentity);
316
496
  return {
317
497
  statusCode: web.HttpStatusCode.noContent
318
498
  };
@@ -329,11 +509,30 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
329
509
  core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
330
510
  core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
331
511
  const component = core.ComponentFactory.get(componentName);
332
- await component.remove(request.pathParams.id, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
512
+ await component.remove(request.pathParams.id, httpRequestContext.userIdentity);
333
513
  return {
334
514
  statusCode: web.HttpStatusCode.noContent
335
515
  };
336
516
  }
517
+ /**
518
+ * List the entries from blob storage.
519
+ * @param httpRequestContext The request context for the API.
520
+ * @param componentName The name of the component to use in the routes.
521
+ * @param request The request.
522
+ * @returns The response object with additional http response properties.
523
+ */
524
+ async function blobStorageList(httpRequestContext, componentName, request) {
525
+ core.Guards.object(ROUTES_SOURCE, "request", request);
526
+ const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
527
+ const component = core.ComponentFactory.get(componentName);
528
+ const result = await component.query(apiModels.HttpParameterHelper.objectFromString(request.query?.conditions), request.query?.orderBy, request.query?.orderByDirection, request.query?.cursor, core.Coerce.number(request.query?.pageSize), httpRequestContext.userIdentity);
529
+ return {
530
+ headers: {
531
+ [web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
532
+ },
533
+ body: result
534
+ };
535
+ }
337
536
 
338
537
  // Copyright 2024 IOTA Stiftung.
339
538
  // SPDX-License-Identifier: Apache-2.0.
@@ -343,8 +542,9 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
343
542
  class BlobStorageService {
344
543
  /**
345
544
  * The namespace supported by the blob storage service.
545
+ * @internal
346
546
  */
347
- static NAMESPACE = "blob";
547
+ static _NAMESPACE = "blob";
348
548
  /**
349
549
  * Runtime name for the class.
350
550
  */
@@ -359,7 +559,7 @@ class BlobStorageService {
359
559
  * The storage connector for the metadata.
360
560
  * @internal
361
561
  */
362
- _metadataEntityStorage;
562
+ _entryEntityStorage;
363
563
  /**
364
564
  * The vault connector for the encryption, can be undefined if no encryption required.
365
565
  * @internal
@@ -371,97 +571,103 @@ class BlobStorageService {
371
571
  */
372
572
  _vaultKeyId;
373
573
  /**
374
- * Include the node identity when performing storage operations, defaults to true.
375
- * @internal
376
- */
377
- _includeNodeIdentity;
378
- /**
379
- * Include the user identity when performing storage operations, defaults to true.
574
+ * Include the user identity when performing storage operations, can be used to partition for users, defaults to false.
380
575
  * @internal
381
576
  */
382
- _includeUserIdentity;
577
+ _partitionPerUser;
383
578
  /**
384
579
  * Create a new instance of BlobStorageService.
385
- * @param options The dependencies for the service.
386
- * @param options.metadataEntityStorageType The type of the storage connector for the metadata, defaults to "blob-metadata".
387
- * @param options.vaultConnectorType The type of the vault connector for encryption, if undefined no encryption will be performed.
388
- * @param options.config The configuration for the service.
580
+ * @param options The options for the service.
389
581
  */
390
582
  constructor(options) {
391
583
  const names = blobStorageModels.BlobStorageConnectorFactory.names();
392
584
  if (names.length === 0) {
393
585
  throw new core.GeneralError(this.CLASS_NAME, "noConnectors");
394
586
  }
395
- this._metadataEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.metadataEntityStorageType ?? "blob-metadata");
587
+ this._entryEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
396
588
  if (core.Is.stringValue(options?.vaultConnectorType)) {
397
- this._vaultConnector = vaultModels.VaultConnectorFactory.getIfExists(options.vaultConnectorType);
589
+ this._vaultConnector = vaultModels.VaultConnectorFactory.get(options.vaultConnectorType);
398
590
  }
399
591
  this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
400
- this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
401
- this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
402
- this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
592
+ this._vaultKeyId = options?.config?.vaultKeyId;
593
+ this._partitionPerUser = options?.config?.partitionPerUser ?? false;
594
+ standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
403
595
  }
404
596
  /**
405
597
  * Create the blob with some metadata.
406
598
  * @param blob The data for the blob in base64 format.
407
- * @param mimeType Mime type for the blob, will be detected if left undefined.
408
- * @param extension Extension for the blob, will be detected if left undefined.
599
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
600
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
409
601
  * @param metadata Data for the custom metadata as JSON-LD.
410
- * @param namespace The namespace to use for storing, defaults to component configured namespace.
602
+ * @param options Optional options for the creation of the blob.
603
+ * @param options.disableEncryption Disables encryption if enabled by default.
604
+ * @param options.overrideVaultKeyId Use a different vault key id for encryption, if not provided the default vault key id will be used.
605
+ * @param options.compress Optional compression type to use for the blob, defaults to no compression.*
606
+ * @param options.namespace The namespace to use for storing, defaults to component configured namespace.
411
607
  * @param userIdentity The user identity to use with storage operations.
412
608
  * @param nodeIdentity The node identity to use with storage operations.
413
609
  * @returns The id of the stored blob in urn format.
414
610
  */
415
- async create(blob, mimeType, extension, metadata, namespace, userIdentity, nodeIdentity) {
611
+ async create(blob, encodingFormat, fileExtension, metadata, options, userIdentity, nodeIdentity) {
416
612
  core.Guards.stringBase64(this.CLASS_NAME, "blob", blob);
417
- if (this._includeUserIdentity) {
613
+ if (this._partitionPerUser) {
418
614
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
419
615
  }
420
- if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
421
- core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
422
- }
616
+ const disableEncryption = options?.disableEncryption ?? false;
617
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
618
+ const encryptionEnabled = !disableEncryption && core.Is.stringValue(vaultKeyId);
423
619
  try {
424
- const connectorNamespace = namespace ?? this._defaultNamespace;
620
+ const connectorNamespace = options?.namespace ?? this._defaultNamespace;
425
621
  const blobStorageConnector = blobStorageModels.BlobStorageConnectorFactory.get(connectorNamespace);
426
622
  // Convert the base64 data into bytes
427
623
  let storeBlob = core.Converter.base64ToBytes(blob);
624
+ const blobSize = storeBlob.length;
428
625
  // See if we can detect the mime type and default extension for the data.
429
626
  // If not already supplied by the caller. We have to perform this operation
430
627
  // on the unencrypted data.
431
- if (!core.Is.stringValue(mimeType)) {
432
- mimeType = await web.MimeTypeHelper.detect(storeBlob);
628
+ if (!core.Is.stringValue(encodingFormat)) {
629
+ encodingFormat = await web.MimeTypeHelper.detect(storeBlob);
433
630
  }
434
- if (!core.Is.stringValue(extension) && core.Is.stringValue(mimeType)) {
435
- extension = await web.MimeTypeHelper.defaultExtension(mimeType);
631
+ if (!core.Is.stringValue(fileExtension) && core.Is.stringValue(encodingFormat)) {
632
+ fileExtension = await web.MimeTypeHelper.defaultExtension(encodingFormat);
436
633
  }
437
634
  if (core.Is.object(metadata)) {
438
635
  const validationFailures = [];
439
636
  dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
440
637
  core.Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
441
638
  }
639
+ const blobHash = `sha256:${core.Converter.bytesToBase64(crypto.Sha256.sum256(storeBlob))}`;
640
+ if (!core.Is.empty(options?.compress)) {
641
+ storeBlob = await core.Compression.compress(storeBlob, options.compress);
642
+ }
442
643
  // If we have a vault connector then encrypt the data.
443
- if (this._vaultConnector) {
444
- storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
644
+ if (encryptionEnabled) {
645
+ core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
646
+ if (core.Is.empty(this._vaultConnector)) {
647
+ throw new core.GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
648
+ }
649
+ storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
445
650
  }
446
651
  // Set the blob in the storage connector, which may now be encrypted
447
652
  const blobId = await blobStorageConnector.set(storeBlob);
448
- // Now store the metadata in entity storage
449
- const blobMetadata = {
653
+ // Now store the entry in entity storage
654
+ const blobEntry = {
450
655
  id: blobId,
451
- mimeType,
452
- extension,
453
- metadata
656
+ dateCreated: new Date(Date.now()).toISOString(),
657
+ blobSize,
658
+ blobHash,
659
+ encodingFormat,
660
+ fileExtension,
661
+ metadata,
662
+ isEncrypted: encryptionEnabled,
663
+ compression: options?.compress
454
664
  };
455
665
  const conditions = [];
456
- if (this._includeUserIdentity) {
457
- core.ObjectHelper.propertySet(blobMetadata, "userIdentity", userIdentity);
666
+ if (this._partitionPerUser) {
667
+ core.ObjectHelper.propertySet(blobEntry, "userIdentity", userIdentity);
458
668
  conditions.push({ property: "userIdentity", value: userIdentity });
459
669
  }
460
- if (this._includeNodeIdentity) {
461
- core.ObjectHelper.propertySet(blobMetadata, "nodeIdentity", nodeIdentity);
462
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
463
- }
464
- await this._metadataEntityStorage.set(blobMetadata, conditions);
670
+ await this._entryEntityStorage.set(blobEntry, conditions);
465
671
  return blobId;
466
672
  }
467
673
  catch (error) {
@@ -469,18 +675,23 @@ class BlobStorageService {
469
675
  }
470
676
  }
471
677
  /**
472
- * Get the blob and metadata.
678
+ * Get the blob entry.
473
679
  * @param id The id of the blob to get in urn format.
474
- * @param includeContent Include the content, or just get the metadata.
680
+ * @param options Optional options for the retrieval of the blob.
681
+ * @param options.includeContent Include the content, or just get the metadata.
682
+ * @param options.overrideVaultKeyId Use a different vault key id for decryption, if not provided the default vault key id will be used.
683
+ * @param options.decompress If the content should be decompressed, if it was compressed when stored, defaults to true.
475
684
  * @param userIdentity The user identity to use with storage operations.
476
685
  * @param nodeIdentity The node identity to use with storage operations.
477
- * @returns The metadata and data for the blob if it can be found.
686
+ * @returns The entry and data for the blob if it can be found.
478
687
  * @throws Not found error if the blob cannot be found.
479
688
  */
480
- async get(id, includeContent, userIdentity, nodeIdentity) {
689
+ async get(id, options, userIdentity, nodeIdentity) {
481
690
  core.Urn.guard(this.CLASS_NAME, "id", id);
691
+ const includeContent = options?.includeContent ?? false;
692
+ const vaultKeyId = options?.overrideVaultKeyId ?? this._vaultKeyId;
482
693
  const conditions = [];
483
- if (this._includeUserIdentity) {
694
+ if (this._partitionPerUser) {
484
695
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
485
696
  conditions.push({
486
697
  property: "userIdentity",
@@ -488,16 +699,8 @@ class BlobStorageService {
488
699
  value: userIdentity
489
700
  });
490
701
  }
491
- if (this._includeNodeIdentity || (core.Is.notEmpty(this._vaultConnector) && includeContent)) {
492
- core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
493
- conditions.push({
494
- property: "nodeIdentity",
495
- comparison: entity.ComparisonOperator.Equals,
496
- value: nodeIdentity
497
- });
498
- }
499
702
  try {
500
- const blobMetadata = await this.internalGet(id, userIdentity, nodeIdentity);
703
+ const blobEntry = await this.internalGet(id, userIdentity);
501
704
  let returnBlob;
502
705
  if (includeContent) {
503
706
  const blobStorageConnector = this.getConnector(id);
@@ -505,17 +708,21 @@ class BlobStorageService {
505
708
  if (core.Is.undefined(returnBlob)) {
506
709
  throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
507
710
  }
508
- // If we have a vault connector then decrypt the data.
509
- if (this._vaultConnector) {
510
- returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
711
+ // If the data is encrypted then decrypt it.
712
+ const decryptionEnabled = blobEntry.isEncrypted && core.Is.stringValue(vaultKeyId);
713
+ if (decryptionEnabled) {
714
+ core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
715
+ if (core.Is.empty(this._vaultConnector)) {
716
+ throw new core.GeneralError(this.CLASS_NAME, "vaultConnectorNotConfigured");
717
+ }
718
+ returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
719
+ }
720
+ if (!core.Is.empty(blobEntry.compression) && (options?.decompress ?? true)) {
721
+ returnBlob = await core.Compression.decompress(returnBlob, blobEntry.compression);
511
722
  }
512
723
  }
513
- return {
514
- blob: core.Is.uint8Array(returnBlob) ? core.Converter.bytesToBase64(returnBlob) : undefined,
515
- mimeType: blobMetadata?.mimeType,
516
- extension: blobMetadata?.extension,
517
- metadata: blobMetadata?.metadata
518
- };
724
+ const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
725
+ return dataJsonLd.JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
519
726
  }
520
727
  catch (error) {
521
728
  throw new core.GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
@@ -523,26 +730,22 @@ class BlobStorageService {
523
730
  }
524
731
  /**
525
732
  * Update the blob with metadata.
526
- * @param id The id of the blob metadata to update.
527
- * @param mimeType Mime type for the blob, will be detected if left undefined.
528
- * @param extension Extension for the blob, will be detected if left undefined.
733
+ * @param id The id of the blob entry to update.
734
+ * @param encodingFormat Mime type for the blob, will be detected if left undefined.
735
+ * @param fileExtension Extension for the blob, will be detected if left undefined.
529
736
  * @param metadata Data for the custom metadata as JSON-LD.
530
737
  * @param userIdentity The user identity to use with storage operations.
531
- * @param nodeIdentity The node identity to use with storage operations.
532
738
  * @returns Nothing.
533
739
  * @throws Not found error if the blob cannot be found.
534
740
  */
535
- async update(id, mimeType, extension, metadata, userIdentity, nodeIdentity) {
741
+ async update(id, encodingFormat, fileExtension, metadata, userIdentity) {
536
742
  core.Urn.guard(this.CLASS_NAME, "id", id);
537
- if (this._includeUserIdentity) {
743
+ if (this._partitionPerUser) {
538
744
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
539
745
  }
540
- if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
541
- core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
542
- }
543
746
  try {
544
- const blobMetadata = await this._metadataEntityStorage.get(id);
545
- if (core.Is.undefined(blobMetadata)) {
747
+ const blobEntry = await this._entryEntityStorage.get(id);
748
+ if (core.Is.undefined(blobEntry)) {
546
749
  throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
547
750
  }
548
751
  if (core.Is.object(metadata)) {
@@ -550,23 +753,25 @@ class BlobStorageService {
550
753
  await dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
551
754
  core.Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
552
755
  }
553
- // Now store the metadata in entity storage
554
- const updatedBlobMetadata = {
555
- id: blobMetadata.id,
556
- mimeType: mimeType ?? blobMetadata.mimeType,
557
- extension: extension ?? blobMetadata.extension,
558
- metadata: metadata ?? blobMetadata.metadata
756
+ // Now store the entry in entity storage
757
+ const updatedBlobEntry = {
758
+ id: blobEntry.id,
759
+ dateCreated: blobEntry.dateCreated,
760
+ dateModified: new Date(Date.now()).toISOString(),
761
+ blobSize: blobEntry.blobSize,
762
+ blobHash: blobEntry.blobHash,
763
+ encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
764
+ fileExtension: fileExtension ?? blobEntry.fileExtension,
765
+ metadata: metadata ?? blobEntry.metadata,
766
+ isEncrypted: blobEntry.isEncrypted,
767
+ compression: blobEntry.compression
559
768
  };
560
769
  const conditions = [];
561
- if (this._includeUserIdentity) {
562
- core.ObjectHelper.propertySet(updatedBlobMetadata, "userIdentity", userIdentity);
770
+ if (this._partitionPerUser) {
771
+ core.ObjectHelper.propertySet(updatedBlobEntry, "userIdentity", userIdentity);
563
772
  conditions.push({ property: "userIdentity", value: userIdentity });
564
773
  }
565
- if (this._includeNodeIdentity) {
566
- core.ObjectHelper.propertySet(updatedBlobMetadata, "nodeIdentity", nodeIdentity);
567
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
568
- }
569
- await this._metadataEntityStorage.set(updatedBlobMetadata, conditions);
774
+ await this._entryEntityStorage.set(updatedBlobEntry, conditions);
570
775
  }
571
776
  catch (error) {
572
777
  throw new core.GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
@@ -576,27 +781,20 @@ class BlobStorageService {
576
781
  * Remove the blob.
577
782
  * @param id The id of the blob to remove in urn format.
578
783
  * @param userIdentity The user identity to use with storage operations.
579
- * @param nodeIdentity The node identity to use with storage operations.
580
784
  * @returns Nothing.
581
785
  */
582
- async remove(id, userIdentity, nodeIdentity) {
786
+ async remove(id, userIdentity) {
583
787
  core.Urn.guard(this.CLASS_NAME, "id", id);
584
- if (this._includeUserIdentity) {
788
+ if (this._partitionPerUser) {
585
789
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
586
790
  }
587
- if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
588
- core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
589
- }
590
791
  try {
591
792
  const blobStorageConnector = this.getConnector(id);
592
793
  const conditions = [];
593
- if (this._includeUserIdentity) {
794
+ if (this._partitionPerUser) {
594
795
  conditions.push({ property: "userIdentity", value: userIdentity });
595
796
  }
596
- if (this._includeNodeIdentity) {
597
- conditions.push({ property: "nodeIdentity", value: nodeIdentity });
598
- }
599
- await this._metadataEntityStorage.remove(id, conditions);
797
+ await this._entryEntityStorage.remove(id, conditions);
600
798
  const removed = await blobStorageConnector.remove(id);
601
799
  if (!removed) {
602
800
  throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
@@ -606,6 +804,60 @@ class BlobStorageService {
606
804
  throw new core.GeneralError(this.CLASS_NAME, "removeFailed", undefined, error);
607
805
  }
608
806
  }
807
+ /**
808
+ * Query all the blob storage entries which match the conditions.
809
+ * @param conditions The conditions to match for the entries.
810
+ * @param orderBy The order for the results, defaults to created.
811
+ * @param orderByDirection The direction for the order, defaults to descending.
812
+ * @param cursor The cursor to request the next page of entries.
813
+ * @param pageSize The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
814
+ * @param userIdentity The user identity to use with storage operations.
815
+ * @returns All the entries for the storage matching the conditions,
816
+ * and a cursor which can be used to request more entities.
817
+ */
818
+ async query(conditions, orderBy, orderByDirection, cursor, pageSize, userIdentity) {
819
+ const finalConditions = {
820
+ conditions: [],
821
+ logicalOperator: entity.LogicalOperator.And
822
+ };
823
+ if (this._partitionPerUser) {
824
+ core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
825
+ finalConditions.conditions.push({
826
+ property: "userIdentity",
827
+ comparison: entity.ComparisonOperator.Equals,
828
+ value: userIdentity
829
+ });
830
+ }
831
+ if (!core.Is.empty(conditions)) {
832
+ finalConditions.conditions.push(conditions);
833
+ }
834
+ const orderProperty = orderBy ?? "dateCreated";
835
+ const orderDirection = orderByDirection ?? entity.SortDirection.Descending;
836
+ const result = await this._entryEntityStorage.query(finalConditions.conditions.length > 0 ? finalConditions : undefined, [
837
+ {
838
+ property: orderProperty,
839
+ sortDirection: orderDirection
840
+ }
841
+ ], undefined, cursor, pageSize);
842
+ let context = [
843
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
844
+ blobStorageModels.BlobStorageContexts.ContextRoot,
845
+ blobStorageModels.BlobStorageContexts.ContextRootCommon
846
+ ];
847
+ const entriesJsonLd = [];
848
+ for (const entry of result.entities) {
849
+ // The entries are never Partial as we don't allow custom property requests.
850
+ entriesJsonLd.push(this.entryToJsonLd(entry));
851
+ context = dataJsonLd.JsonLdProcessor.combineContexts(context, entry.metadata?.["@context"]);
852
+ }
853
+ const jsonLd = {
854
+ "@context": context,
855
+ type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
856
+ [standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: entriesJsonLd,
857
+ [standardsSchemaOrg.SchemaOrgTypes.NextItem]: result.cursor
858
+ };
859
+ return dataJsonLd.JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
860
+ }
609
861
  /**
610
862
  * Get the connector from the uri.
611
863
  * @param id The id of the blob storage item in urn format.
@@ -614,9 +866,9 @@ class BlobStorageService {
614
866
  */
615
867
  getConnector(id) {
616
868
  const idUri = core.Urn.fromValidString(id);
617
- if (idUri.namespaceIdentifier() !== BlobStorageService.NAMESPACE) {
869
+ if (idUri.namespaceIdentifier() !== BlobStorageService._NAMESPACE) {
618
870
  throw new core.GeneralError(this.CLASS_NAME, "namespaceMismatch", {
619
- namespace: BlobStorageService.NAMESPACE,
871
+ namespace: BlobStorageService._NAMESPACE,
620
872
  id
621
873
  });
622
874
  }
@@ -627,13 +879,12 @@ class BlobStorageService {
627
879
  * @param id The id of the entity to get, or the index value if secondaryIndex is set.
628
880
  * @param secondaryIndex Get the item using a secondary index.
629
881
  * @param userIdentity The user identity to use with storage operations.
630
- * @param nodeIdentity The node identity to use with storage operations.
631
882
  * @returns The object if it can be found or throws.
632
883
  * @internal
633
884
  */
634
- async internalGet(id, userIdentity, nodeIdentity) {
885
+ async internalGet(id, userIdentity) {
635
886
  const conditions = [];
636
- if (this._includeUserIdentity) {
887
+ if (this._partitionPerUser) {
637
888
  core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
638
889
  conditions.push({
639
890
  property: "userIdentity",
@@ -641,27 +892,19 @@ class BlobStorageService {
641
892
  value: userIdentity
642
893
  });
643
894
  }
644
- if (this._includeNodeIdentity) {
645
- core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
646
- conditions.push({
647
- property: "nodeIdentity",
648
- comparison: entity.ComparisonOperator.Equals,
649
- value: nodeIdentity
650
- });
651
- }
652
895
  let entity$1;
653
896
  if (conditions.length === 0) {
654
- entity$1 = await this._metadataEntityStorage.get(id);
897
+ entity$1 = await this._entryEntityStorage.get(id);
655
898
  }
656
899
  else {
657
- const schema = this._metadataEntityStorage.getSchema();
900
+ const schema = this._entryEntityStorage.getSchema();
658
901
  const primaryKey = entity.EntitySchemaHelper.getPrimaryKey(schema);
659
902
  conditions.unshift({
660
903
  property: primaryKey.property,
661
904
  comparison: entity.ComparisonOperator.Equals,
662
905
  value: id
663
906
  });
664
- const results = await this._metadataEntityStorage.query({
907
+ const results = await this._entryEntityStorage.query({
665
908
  conditions,
666
909
  logicalOperator: entity.LogicalOperator.And
667
910
  }, undefined, undefined, undefined, 1);
@@ -670,68 +913,140 @@ class BlobStorageService {
670
913
  if (core.Is.empty(entity$1)) {
671
914
  throw new core.NotFoundError(this.CLASS_NAME, "entityNotFound", id);
672
915
  }
673
- core.ObjectHelper.propertyDelete(entity$1, "nodeIdentity");
674
- core.ObjectHelper.propertyDelete(entity$1, "userIdentity");
675
- return entity$1;
916
+ return core.ObjectHelper.omit(entity$1, ["userIdentity"]);
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": dataJsonLd.JsonLdProcessor.combineContexts([
928
+ blobStorageModels.BlobStorageContexts.ContextRoot,
929
+ blobStorageModels.BlobStorageContexts.ContextRootCommon,
930
+ standardsSchemaOrg.SchemaOrgContexts.ContextRoot
931
+ ], entry?.metadata?.["@context"]),
932
+ id: entry.id,
933
+ type: blobStorageModels.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: core.Is.uint8Array(blob) ? core.Converter.bytesToBase64(blob) : undefined,
942
+ isEncrypted: entry.isEncrypted,
943
+ compression: entry.compression
944
+ };
945
+ return jsonLd;
676
946
  }
677
947
  }
678
948
 
679
949
  /**
680
- * Class representing metadata for the blob storage.
950
+ * Class representing entry for the blob storage.
681
951
  */
682
- exports.BlobMetadata = class BlobMetadata {
952
+ exports.BlobStorageEntry = class BlobStorageEntry {
683
953
  /**
684
954
  * The id for the blob.
685
955
  */
686
956
  id;
957
+ /**
958
+ * The date/time when the entry was created.
959
+ */
960
+ dateCreated;
961
+ /**
962
+ * The date/time when the entry was modified.
963
+ */
964
+ dateModified;
965
+ /**
966
+ * The length of the data in the blob.
967
+ */
968
+ blobSize;
969
+ /**
970
+ * The hash of the data in the blob.
971
+ */
972
+ blobHash;
687
973
  /**
688
974
  * The mime type for the blob.
689
975
  */
690
- mimeType;
976
+ encodingFormat;
691
977
  /**
692
978
  * The extension.
693
979
  */
694
- extension;
980
+ fileExtension;
695
981
  /**
696
982
  * The metadata for the blob as JSON-LD.
697
983
  */
698
984
  metadata;
699
985
  /**
700
- * The user identity that created the blob.
986
+ * Is the entry encrypted.
701
987
  */
702
- userIdentity;
988
+ isEncrypted;
703
989
  /**
704
- * The node identity that created the blob.
990
+ * Is the entry compressed.
991
+ */
992
+ compression;
993
+ /**
994
+ * The user identity that created the blob.
705
995
  */
706
- nodeIdentity;
996
+ userIdentity;
707
997
  };
708
998
  __decorate([
709
999
  entity.property({ type: "string", isPrimary: true }),
710
1000
  __metadata("design:type", String)
711
- ], exports.BlobMetadata.prototype, "id", void 0);
1001
+ ], exports.BlobStorageEntry.prototype, "id", void 0);
712
1002
  __decorate([
713
- entity.property({ type: "string" }),
1003
+ entity.property({ type: "string", format: "date-time", sortDirection: entity.SortDirection.Descending }),
1004
+ __metadata("design:type", String)
1005
+ ], exports.BlobStorageEntry.prototype, "dateCreated", void 0);
1006
+ __decorate([
1007
+ entity.property({
1008
+ type: "string",
1009
+ format: "date-time",
1010
+ sortDirection: entity.SortDirection.Descending,
1011
+ optional: true
1012
+ }),
714
1013
  __metadata("design:type", String)
715
- ], exports.BlobMetadata.prototype, "mimeType", void 0);
1014
+ ], exports.BlobStorageEntry.prototype, "dateModified", void 0);
1015
+ __decorate([
1016
+ entity.property({ type: "number" }),
1017
+ __metadata("design:type", Number)
1018
+ ], exports.BlobStorageEntry.prototype, "blobSize", void 0);
716
1019
  __decorate([
717
1020
  entity.property({ type: "string" }),
718
1021
  __metadata("design:type", String)
719
- ], exports.BlobMetadata.prototype, "extension", void 0);
1022
+ ], exports.BlobStorageEntry.prototype, "blobHash", void 0);
1023
+ __decorate([
1024
+ entity.property({ type: "string", optional: true }),
1025
+ __metadata("design:type", String)
1026
+ ], exports.BlobStorageEntry.prototype, "encodingFormat", void 0);
1027
+ __decorate([
1028
+ entity.property({ type: "string", optional: true }),
1029
+ __metadata("design:type", String)
1030
+ ], exports.BlobStorageEntry.prototype, "fileExtension", void 0);
720
1031
  __decorate([
721
- entity.property({ type: "object", itemTypeRef: "IJsonLdNodeObject" }),
1032
+ entity.property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
722
1033
  __metadata("design:type", Object)
723
- ], exports.BlobMetadata.prototype, "metadata", void 0);
1034
+ ], exports.BlobStorageEntry.prototype, "metadata", void 0);
724
1035
  __decorate([
725
- entity.property({ type: "string" }),
1036
+ entity.property({ type: "boolean" }),
1037
+ __metadata("design:type", Boolean)
1038
+ ], exports.BlobStorageEntry.prototype, "isEncrypted", void 0);
1039
+ __decorate([
1040
+ entity.property({ type: "string", optional: true }),
726
1041
  __metadata("design:type", String)
727
- ], exports.BlobMetadata.prototype, "userIdentity", void 0);
1042
+ ], exports.BlobStorageEntry.prototype, "compression", void 0);
728
1043
  __decorate([
729
- entity.property({ type: "string" }),
1044
+ entity.property({ type: "string", optional: true }),
730
1045
  __metadata("design:type", String)
731
- ], exports.BlobMetadata.prototype, "nodeIdentity", void 0);
732
- exports.BlobMetadata = __decorate([
1046
+ ], exports.BlobStorageEntry.prototype, "userIdentity", void 0);
1047
+ exports.BlobStorageEntry = __decorate([
733
1048
  entity.entity()
734
- ], exports.BlobMetadata);
1049
+ ], exports.BlobStorageEntry);
735
1050
 
736
1051
  /**
737
1052
  * These are dummy entry points for the blob storage service.
@@ -753,13 +1068,14 @@ const restEntryPoints = [
753
1068
  * Initialize the schema for the blob storage entities.
754
1069
  */
755
1070
  function initSchema() {
756
- entity.EntitySchemaFactory.register("BlobMetadata", () => entity.EntitySchemaHelper.getSchema(exports.BlobMetadata));
1071
+ entity.EntitySchemaFactory.register("BlobStorageEntry", () => entity.EntitySchemaHelper.getSchema(exports.BlobStorageEntry));
757
1072
  }
758
1073
 
759
1074
  exports.BlobStorageService = BlobStorageService;
760
1075
  exports.blobStorageCreate = blobStorageCreate;
761
1076
  exports.blobStorageGet = blobStorageGet;
762
1077
  exports.blobStorageGetContent = blobStorageGetContent;
1078
+ exports.blobStorageList = blobStorageList;
763
1079
  exports.blobStorageRemove = blobStorageRemove;
764
1080
  exports.blobStorageUpdate = blobStorageUpdate;
765
1081
  exports.generateRestRoutesBlobStorage = generateRestRoutesBlobStorage;