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