@twin.org/blob-storage-service 0.0.1-next.3 → 0.0.1-next.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +563 -101
- package/dist/esm/index.mjs +565 -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 +33 -1
- package/docs/open-api/spec.json +2241 -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,114 @@ 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
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
305
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon
|
|
306
|
+
],
|
|
307
|
+
type: blobStorageModels.BlobStorageTypes.EntryList,
|
|
308
|
+
entries: [
|
|
309
|
+
{
|
|
310
|
+
"@context": [
|
|
311
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
312
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon,
|
|
313
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
314
|
+
],
|
|
315
|
+
type: blobStorageModels.BlobStorageTypes.Entry,
|
|
316
|
+
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
317
|
+
dateCreated: "2024-01-01T00:00:00Z",
|
|
318
|
+
encodingFormat: web.MimeTypes.Pdf,
|
|
319
|
+
blobSize: 42,
|
|
320
|
+
blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
321
|
+
fileExtension: "pdf",
|
|
322
|
+
metadata: {
|
|
323
|
+
"@context": "https://schema.org",
|
|
324
|
+
"@type": "DigitalDocument",
|
|
325
|
+
name: "myfile.pdf"
|
|
326
|
+
},
|
|
327
|
+
blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
|
|
328
|
+
}
|
|
329
|
+
]
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
type: "IBlobStorageListResponse",
|
|
337
|
+
mimeType: web.MimeTypes.JsonLd,
|
|
338
|
+
examples: [
|
|
339
|
+
{
|
|
340
|
+
id: `${camelTypeName}ListResponseJsonLdExample`,
|
|
341
|
+
response: {
|
|
342
|
+
body: {
|
|
343
|
+
"@context": [
|
|
344
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
345
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon
|
|
346
|
+
],
|
|
347
|
+
type: blobStorageModels.BlobStorageTypes.EntryList,
|
|
348
|
+
entries: [
|
|
349
|
+
{
|
|
350
|
+
"@context": [
|
|
351
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
352
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon,
|
|
353
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
354
|
+
],
|
|
355
|
+
type: blobStorageModels.BlobStorageTypes.Entry,
|
|
356
|
+
id: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
357
|
+
dateCreated: "2024-01-01T00:00:00Z",
|
|
358
|
+
encodingFormat: web.MimeTypes.Pdf,
|
|
359
|
+
blobSize: 42,
|
|
360
|
+
blobHash: "sha256:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
361
|
+
fileExtension: "pdf",
|
|
362
|
+
metadata: {
|
|
363
|
+
"@context": "https://schema.org",
|
|
364
|
+
"@type": "DigitalDocument",
|
|
365
|
+
name: "myfile.pdf"
|
|
366
|
+
},
|
|
367
|
+
blob: "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="
|
|
368
|
+
}
|
|
369
|
+
]
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
type: "INotFoundResponse"
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
};
|
|
225
380
|
return [
|
|
226
381
|
blobStorageCreateRoute,
|
|
227
382
|
blobStorageGetRoute,
|
|
228
383
|
blobStorageGetContentRoute,
|
|
229
384
|
blobStorageUpdateRoute,
|
|
230
|
-
blobStorageRemoveRoute
|
|
385
|
+
blobStorageRemoveRoute,
|
|
386
|
+
blobStorageListRoute
|
|
231
387
|
];
|
|
232
388
|
}
|
|
233
389
|
/**
|
|
@@ -242,11 +398,11 @@ async function blobStorageCreate(httpRequestContext, componentName, request) {
|
|
|
242
398
|
core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
|
|
243
399
|
core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
|
|
244
400
|
const component = core.ComponentFactory.get(componentName);
|
|
245
|
-
const id = await component.create(request.body.blob, request.body.
|
|
401
|
+
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
402
|
return {
|
|
247
403
|
statusCode: web.HttpStatusCode.created,
|
|
248
404
|
headers: {
|
|
249
|
-
|
|
405
|
+
location: id
|
|
250
406
|
}
|
|
251
407
|
};
|
|
252
408
|
}
|
|
@@ -261,9 +417,13 @@ async function blobStorageGet(httpRequestContext, componentName, request) {
|
|
|
261
417
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
262
418
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
263
419
|
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
420
|
+
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
264
421
|
const component = core.ComponentFactory.get(componentName);
|
|
265
|
-
const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.nodeIdentity);
|
|
422
|
+
const result = await component.get(request.pathParams.id, request.query?.includeContent ?? false, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
266
423
|
return {
|
|
424
|
+
headers: {
|
|
425
|
+
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
426
|
+
},
|
|
267
427
|
body: result
|
|
268
428
|
};
|
|
269
429
|
}
|
|
@@ -279,16 +439,16 @@ async function blobStorageGetContent(httpRequestContext, componentName, request)
|
|
|
279
439
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
280
440
|
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
281
441
|
const component = core.ComponentFactory.get(componentName);
|
|
282
|
-
const result = await component.get(request.pathParams.id, true, httpRequestContext.nodeIdentity);
|
|
283
|
-
const
|
|
442
|
+
const result = await component.get(request.pathParams.id, true, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
443
|
+
const encodingFormat = result?.encodingFormat ?? web.MimeTypes.OctetStream;
|
|
284
444
|
let filename = request.query?.filename;
|
|
285
445
|
if (!core.Is.stringValue(filename)) {
|
|
286
|
-
filename = `file.${result.
|
|
446
|
+
filename = `file.${result.fileExtension ?? web.MimeTypeHelper.defaultExtension(encodingFormat)}`;
|
|
287
447
|
}
|
|
288
448
|
return {
|
|
289
449
|
body: core.Is.stringBase64(result.blob) ? core.Converter.base64ToBytes(result.blob) : new Uint8Array(),
|
|
290
450
|
attachment: {
|
|
291
|
-
mimeType,
|
|
451
|
+
mimeType: encodingFormat,
|
|
292
452
|
filename,
|
|
293
453
|
inline: !(request.query?.download ?? false)
|
|
294
454
|
}
|
|
@@ -306,7 +466,7 @@ async function blobStorageUpdate(httpRequestContext, componentName, request) {
|
|
|
306
466
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
307
467
|
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
308
468
|
const component = core.ComponentFactory.get(componentName);
|
|
309
|
-
await component.update(request.pathParams.id, request.body.
|
|
469
|
+
await component.update(request.pathParams.id, request.body.encodingFormat, request.body.fileExtension, request.body.metadata, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
310
470
|
return {
|
|
311
471
|
statusCode: web.HttpStatusCode.noContent
|
|
312
472
|
};
|
|
@@ -323,11 +483,30 @@ async function blobStorageRemove(httpRequestContext, componentName, request) {
|
|
|
323
483
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
324
484
|
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.id", request.pathParams.id);
|
|
325
485
|
const component = core.ComponentFactory.get(componentName);
|
|
326
|
-
await component.remove(request.pathParams.id);
|
|
486
|
+
await component.remove(request.pathParams.id, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
327
487
|
return {
|
|
328
488
|
statusCode: web.HttpStatusCode.noContent
|
|
329
489
|
};
|
|
330
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* List the entries from blob storage.
|
|
493
|
+
* @param httpRequestContext The request context for the API.
|
|
494
|
+
* @param componentName The name of the component to use in the routes.
|
|
495
|
+
* @param request The request.
|
|
496
|
+
* @returns The response object with additional http response properties.
|
|
497
|
+
*/
|
|
498
|
+
async function blobStorageList(httpRequestContext, componentName, request) {
|
|
499
|
+
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
500
|
+
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
501
|
+
const component = core.ComponentFactory.get(componentName);
|
|
502
|
+
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);
|
|
503
|
+
return {
|
|
504
|
+
headers: {
|
|
505
|
+
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
506
|
+
},
|
|
507
|
+
body: result
|
|
508
|
+
};
|
|
509
|
+
}
|
|
331
510
|
|
|
332
511
|
// Copyright 2024 IOTA Stiftung.
|
|
333
512
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -353,7 +532,7 @@ class BlobStorageService {
|
|
|
353
532
|
* The storage connector for the metadata.
|
|
354
533
|
* @internal
|
|
355
534
|
*/
|
|
356
|
-
|
|
535
|
+
_entryEntityStorage;
|
|
357
536
|
/**
|
|
358
537
|
* The vault connector for the encryption, can be undefined if no encryption required.
|
|
359
538
|
* @internal
|
|
@@ -364,38 +543,52 @@ class BlobStorageService {
|
|
|
364
543
|
* @internal
|
|
365
544
|
*/
|
|
366
545
|
_vaultKeyId;
|
|
546
|
+
/**
|
|
547
|
+
* Include the node identity when performing storage operations, defaults to true.
|
|
548
|
+
* @internal
|
|
549
|
+
*/
|
|
550
|
+
_includeNodeIdentity;
|
|
551
|
+
/**
|
|
552
|
+
* Include the user identity when performing storage operations, defaults to true.
|
|
553
|
+
* @internal
|
|
554
|
+
*/
|
|
555
|
+
_includeUserIdentity;
|
|
367
556
|
/**
|
|
368
557
|
* 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.
|
|
558
|
+
* @param options The options for the service.
|
|
373
559
|
*/
|
|
374
560
|
constructor(options) {
|
|
375
561
|
const names = blobStorageModels.BlobStorageConnectorFactory.names();
|
|
376
562
|
if (names.length === 0) {
|
|
377
563
|
throw new core.GeneralError(this.CLASS_NAME, "noConnectors");
|
|
378
564
|
}
|
|
379
|
-
this.
|
|
565
|
+
this._entryEntityStorage = entityStorageModels.EntityStorageConnectorFactory.get(options?.entryEntityStorageType ?? "blob-storage-entry");
|
|
380
566
|
if (core.Is.stringValue(options?.vaultConnectorType)) {
|
|
381
567
|
this._vaultConnector = vaultModels.VaultConnectorFactory.getIfExists(options.vaultConnectorType);
|
|
382
568
|
}
|
|
383
569
|
this._defaultNamespace = options?.config?.defaultNamespace ?? names[0];
|
|
384
570
|
this._vaultKeyId = options?.config?.vaultKeyId ?? "blob-storage";
|
|
571
|
+
this._includeNodeIdentity = options?.config?.includeNodeIdentity ?? true;
|
|
572
|
+
this._includeUserIdentity = options?.config?.includeUserIdentity ?? true;
|
|
573
|
+
standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
|
|
385
574
|
}
|
|
386
575
|
/**
|
|
387
576
|
* Create the blob with some metadata.
|
|
388
577
|
* @param blob The data for the blob in base64 format.
|
|
389
|
-
* @param
|
|
390
|
-
* @param
|
|
578
|
+
* @param encodingFormat Mime type for the blob, will be detected if left undefined.
|
|
579
|
+
* @param fileExtension Extension for the blob, will be detected if left undefined.
|
|
391
580
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
392
581
|
* @param namespace The namespace to use for storing, defaults to component configured namespace.
|
|
393
|
-
* @param
|
|
582
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
583
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
394
584
|
* @returns The id of the stored blob in urn format.
|
|
395
585
|
*/
|
|
396
|
-
async create(blob,
|
|
586
|
+
async create(blob, encodingFormat, fileExtension, metadata, namespace, userIdentity, nodeIdentity) {
|
|
397
587
|
core.Guards.stringBase64(this.CLASS_NAME, "blob", blob);
|
|
398
|
-
if (this.
|
|
588
|
+
if (this._includeUserIdentity) {
|
|
589
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
590
|
+
}
|
|
591
|
+
if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
|
|
399
592
|
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
400
593
|
}
|
|
401
594
|
try {
|
|
@@ -403,32 +596,48 @@ class BlobStorageService {
|
|
|
403
596
|
const blobStorageConnector = blobStorageModels.BlobStorageConnectorFactory.get(connectorNamespace);
|
|
404
597
|
// Convert the base64 data into bytes
|
|
405
598
|
let storeBlob = core.Converter.base64ToBytes(blob);
|
|
599
|
+
const blobSize = storeBlob.length;
|
|
406
600
|
// See if we can detect the mime type and default extension for the data.
|
|
407
601
|
// If not already supplied by the caller. We have to perform this operation
|
|
408
602
|
// on the unencrypted data.
|
|
409
|
-
if (!core.Is.stringValue(
|
|
410
|
-
|
|
603
|
+
if (!core.Is.stringValue(encodingFormat)) {
|
|
604
|
+
encodingFormat = await web.MimeTypeHelper.detect(storeBlob);
|
|
411
605
|
}
|
|
412
|
-
if (!core.Is.stringValue(
|
|
413
|
-
|
|
606
|
+
if (!core.Is.stringValue(fileExtension) && core.Is.stringValue(encodingFormat)) {
|
|
607
|
+
fileExtension = await web.MimeTypeHelper.defaultExtension(encodingFormat);
|
|
414
608
|
}
|
|
415
609
|
if (core.Is.object(metadata)) {
|
|
416
610
|
const validationFailures = [];
|
|
417
611
|
dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
|
|
418
612
|
core.Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
|
|
419
613
|
}
|
|
614
|
+
const blobHash = `sha256:${core.Converter.bytesToBase64(crypto.Sha256.sum256(storeBlob))}`;
|
|
420
615
|
// If we have a vault connector then encrypt the data.
|
|
421
616
|
if (this._vaultConnector) {
|
|
422
617
|
storeBlob = await this._vaultConnector.encrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, storeBlob);
|
|
423
618
|
}
|
|
424
619
|
// Set the blob in the storage connector, which may now be encrypted
|
|
425
620
|
const blobId = await blobStorageConnector.set(storeBlob);
|
|
426
|
-
|
|
621
|
+
// Now store the entry in entity storage
|
|
622
|
+
const blobEntry = {
|
|
427
623
|
id: blobId,
|
|
428
|
-
|
|
429
|
-
|
|
624
|
+
dateCreated: new Date(Date.now()).toISOString(),
|
|
625
|
+
blobSize,
|
|
626
|
+
blobHash,
|
|
627
|
+
encodingFormat,
|
|
628
|
+
fileExtension,
|
|
430
629
|
metadata
|
|
431
|
-
}
|
|
630
|
+
};
|
|
631
|
+
const conditions = [];
|
|
632
|
+
if (this._includeUserIdentity) {
|
|
633
|
+
core.ObjectHelper.propertySet(blobEntry, "userIdentity", userIdentity);
|
|
634
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
635
|
+
}
|
|
636
|
+
if (this._includeNodeIdentity) {
|
|
637
|
+
core.ObjectHelper.propertySet(blobEntry, "nodeIdentity", nodeIdentity);
|
|
638
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
639
|
+
}
|
|
640
|
+
await this._entryEntityStorage.set(blobEntry, conditions);
|
|
432
641
|
return blobId;
|
|
433
642
|
}
|
|
434
643
|
catch (error) {
|
|
@@ -436,21 +645,35 @@ class BlobStorageService {
|
|
|
436
645
|
}
|
|
437
646
|
}
|
|
438
647
|
/**
|
|
439
|
-
* Get the blob
|
|
648
|
+
* Get the blob entry.
|
|
440
649
|
* @param id The id of the blob to get in urn format.
|
|
441
650
|
* @param includeContent Include the content, or just get the metadata.
|
|
442
|
-
* @param
|
|
443
|
-
* @
|
|
651
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
652
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
653
|
+
* @returns The entry and data for the blob if it can be found.
|
|
444
654
|
* @throws Not found error if the blob cannot be found.
|
|
445
655
|
*/
|
|
446
|
-
async get(id, includeContent, nodeIdentity) {
|
|
656
|
+
async get(id, includeContent, userIdentity, nodeIdentity) {
|
|
447
657
|
core.Urn.guard(this.CLASS_NAME, "id", id);
|
|
448
|
-
|
|
658
|
+
const conditions = [];
|
|
659
|
+
if (this._includeUserIdentity) {
|
|
660
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
661
|
+
conditions.push({
|
|
662
|
+
property: "userIdentity",
|
|
663
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
664
|
+
value: userIdentity
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
if (this._includeNodeIdentity || (core.Is.notEmpty(this._vaultConnector) && includeContent)) {
|
|
449
668
|
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
669
|
+
conditions.push({
|
|
670
|
+
property: "nodeIdentity",
|
|
671
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
672
|
+
value: nodeIdentity
|
|
673
|
+
});
|
|
450
674
|
}
|
|
451
675
|
try {
|
|
452
|
-
|
|
453
|
-
const blobMetadata = await this._metadataEntityStorage.get(id);
|
|
676
|
+
const blobEntry = await this.internalGet(id, userIdentity, nodeIdentity);
|
|
454
677
|
let returnBlob;
|
|
455
678
|
if (includeContent) {
|
|
456
679
|
const blobStorageConnector = this.getConnector(id);
|
|
@@ -463,12 +686,8 @@ class BlobStorageService {
|
|
|
463
686
|
returnBlob = await this._vaultConnector.decrypt(`${nodeIdentity}/${this._vaultKeyId}`, vaultModels.VaultEncryptionType.ChaCha20Poly1305, returnBlob);
|
|
464
687
|
}
|
|
465
688
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
mimeType: blobMetadata?.mimeType,
|
|
469
|
-
extension: blobMetadata?.extension,
|
|
470
|
-
metadata: blobMetadata?.metadata
|
|
471
|
-
};
|
|
689
|
+
const jsonLd = this.entryToJsonLd(blobEntry, returnBlob);
|
|
690
|
+
return dataJsonLd.JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
472
691
|
}
|
|
473
692
|
catch (error) {
|
|
474
693
|
throw new core.GeneralError(this.CLASS_NAME, "getFailed", undefined, error);
|
|
@@ -476,18 +695,26 @@ class BlobStorageService {
|
|
|
476
695
|
}
|
|
477
696
|
/**
|
|
478
697
|
* Update the blob with metadata.
|
|
479
|
-
* @param id The id of the blob
|
|
480
|
-
* @param
|
|
481
|
-
* @param
|
|
698
|
+
* @param id The id of the blob entry to update.
|
|
699
|
+
* @param encodingFormat Mime type for the blob, will be detected if left undefined.
|
|
700
|
+
* @param fileExtension Extension for the blob, will be detected if left undefined.
|
|
482
701
|
* @param metadata Data for the custom metadata as JSON-LD.
|
|
702
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
703
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
483
704
|
* @returns Nothing.
|
|
484
705
|
* @throws Not found error if the blob cannot be found.
|
|
485
706
|
*/
|
|
486
|
-
async update(id,
|
|
707
|
+
async update(id, encodingFormat, fileExtension, metadata, userIdentity, nodeIdentity) {
|
|
487
708
|
core.Urn.guard(this.CLASS_NAME, "id", id);
|
|
709
|
+
if (this._includeUserIdentity) {
|
|
710
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
711
|
+
}
|
|
712
|
+
if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
|
|
713
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
714
|
+
}
|
|
488
715
|
try {
|
|
489
|
-
const
|
|
490
|
-
if (core.Is.undefined(
|
|
716
|
+
const blobEntry = await this._entryEntityStorage.get(id);
|
|
717
|
+
if (core.Is.undefined(blobEntry)) {
|
|
491
718
|
throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
|
|
492
719
|
}
|
|
493
720
|
if (core.Is.object(metadata)) {
|
|
@@ -495,12 +722,27 @@ class BlobStorageService {
|
|
|
495
722
|
await dataJsonLd.JsonLdHelper.validate(metadata, validationFailures);
|
|
496
723
|
core.Validation.asValidationError(this.CLASS_NAME, "metadata", validationFailures);
|
|
497
724
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
725
|
+
// Now store the entry in entity storage
|
|
726
|
+
const updatedBlobEntry = {
|
|
727
|
+
id: blobEntry.id,
|
|
728
|
+
dateCreated: blobEntry.dateCreated,
|
|
729
|
+
dateModified: new Date(Date.now()).toISOString(),
|
|
730
|
+
blobSize: blobEntry.blobSize,
|
|
731
|
+
blobHash: blobEntry.blobHash,
|
|
732
|
+
encodingFormat: encodingFormat ?? blobEntry.encodingFormat,
|
|
733
|
+
fileExtension: fileExtension ?? blobEntry.fileExtension,
|
|
734
|
+
metadata: metadata ?? blobEntry.metadata
|
|
735
|
+
};
|
|
736
|
+
const conditions = [];
|
|
737
|
+
if (this._includeUserIdentity) {
|
|
738
|
+
core.ObjectHelper.propertySet(updatedBlobEntry, "userIdentity", userIdentity);
|
|
739
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
740
|
+
}
|
|
741
|
+
if (this._includeNodeIdentity) {
|
|
742
|
+
core.ObjectHelper.propertySet(updatedBlobEntry, "nodeIdentity", nodeIdentity);
|
|
743
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
744
|
+
}
|
|
745
|
+
await this._entryEntityStorage.set(updatedBlobEntry, conditions);
|
|
504
746
|
}
|
|
505
747
|
catch (error) {
|
|
506
748
|
throw new core.GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
|
|
@@ -509,22 +751,104 @@ class BlobStorageService {
|
|
|
509
751
|
/**
|
|
510
752
|
* Remove the blob.
|
|
511
753
|
* @param id The id of the blob to remove in urn format.
|
|
754
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
755
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
512
756
|
* @returns Nothing.
|
|
513
757
|
*/
|
|
514
|
-
async remove(id) {
|
|
758
|
+
async remove(id, userIdentity, nodeIdentity) {
|
|
515
759
|
core.Urn.guard(this.CLASS_NAME, "id", id);
|
|
760
|
+
if (this._includeUserIdentity) {
|
|
761
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
762
|
+
}
|
|
763
|
+
if (this._includeNodeIdentity || core.Is.notEmpty(this._vaultConnector)) {
|
|
764
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
765
|
+
}
|
|
516
766
|
try {
|
|
517
767
|
const blobStorageConnector = this.getConnector(id);
|
|
768
|
+
const conditions = [];
|
|
769
|
+
if (this._includeUserIdentity) {
|
|
770
|
+
conditions.push({ property: "userIdentity", value: userIdentity });
|
|
771
|
+
}
|
|
772
|
+
if (this._includeNodeIdentity) {
|
|
773
|
+
conditions.push({ property: "nodeIdentity", value: nodeIdentity });
|
|
774
|
+
}
|
|
775
|
+
await this._entryEntityStorage.remove(id, conditions);
|
|
518
776
|
const removed = await blobStorageConnector.remove(id);
|
|
519
777
|
if (!removed) {
|
|
520
778
|
throw new core.NotFoundError(this.CLASS_NAME, "blobNotFound", id);
|
|
521
779
|
}
|
|
522
|
-
await this._metadataEntityStorage.remove(id);
|
|
523
780
|
}
|
|
524
781
|
catch (error) {
|
|
525
782
|
throw new core.GeneralError(this.CLASS_NAME, "removeFailed", undefined, error);
|
|
526
783
|
}
|
|
527
784
|
}
|
|
785
|
+
/**
|
|
786
|
+
* Query all the blob storage entries which match the conditions.
|
|
787
|
+
* @param conditions The conditions to match for the entries.
|
|
788
|
+
* @param orderBy The order for the results, defaults to created.
|
|
789
|
+
* @param orderByDirection The direction for the order, defaults to descending.
|
|
790
|
+
* @param cursor The cursor to request the next page of entries.
|
|
791
|
+
* @param pageSize The suggested number of entries to return in each chunk, in some scenarios can return a different amount.
|
|
792
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
793
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
794
|
+
* @returns All the entries for the storage matching the conditions,
|
|
795
|
+
* and a cursor which can be used to request more entities.
|
|
796
|
+
*/
|
|
797
|
+
async query(conditions, orderBy, orderByDirection, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
798
|
+
const finalConditions = {
|
|
799
|
+
conditions: [],
|
|
800
|
+
logicalOperator: entity.LogicalOperator.And
|
|
801
|
+
};
|
|
802
|
+
if (this._includeNodeIdentity) {
|
|
803
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
804
|
+
finalConditions.conditions.push({
|
|
805
|
+
property: "nodeIdentity",
|
|
806
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
807
|
+
value: nodeIdentity
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
if (this._includeUserIdentity) {
|
|
811
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
812
|
+
finalConditions.conditions.push({
|
|
813
|
+
property: "userIdentity",
|
|
814
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
815
|
+
value: userIdentity
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
if (!core.Is.empty(conditions)) {
|
|
819
|
+
finalConditions.conditions.push(conditions);
|
|
820
|
+
}
|
|
821
|
+
const orderProperty = orderBy ?? "dateCreated";
|
|
822
|
+
const orderDirection = orderByDirection ?? entity.SortDirection.Descending;
|
|
823
|
+
const result = await this._entryEntityStorage.query(finalConditions.conditions.length > 0 ? finalConditions : undefined, [
|
|
824
|
+
{
|
|
825
|
+
property: orderProperty,
|
|
826
|
+
sortDirection: orderDirection
|
|
827
|
+
}
|
|
828
|
+
], undefined, cursor, pageSize);
|
|
829
|
+
for (const entity of result.entities) {
|
|
830
|
+
core.ObjectHelper.propertyDelete(entity, "nodeIdentity");
|
|
831
|
+
core.ObjectHelper.propertyDelete(entity, "userIdentity");
|
|
832
|
+
}
|
|
833
|
+
let context = [
|
|
834
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
835
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon,
|
|
836
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
837
|
+
];
|
|
838
|
+
const entriesJsonLd = [];
|
|
839
|
+
for (const entry of result.entities) {
|
|
840
|
+
// The entries are never Partial as we don't allow custom property requests.
|
|
841
|
+
entriesJsonLd.push(this.entryToJsonLd(entry));
|
|
842
|
+
context = dataJsonLd.JsonLdProcessor.combineContexts(context, entry.metadata?.["@context"]);
|
|
843
|
+
}
|
|
844
|
+
const jsonLd = {
|
|
845
|
+
"@context": context,
|
|
846
|
+
type: blobStorageModels.BlobStorageTypes.EntryList,
|
|
847
|
+
entries: entriesJsonLd,
|
|
848
|
+
cursor: result.cursor
|
|
849
|
+
};
|
|
850
|
+
return dataJsonLd.JsonLdProcessor.compact(jsonLd, jsonLd["@context"]);
|
|
851
|
+
}
|
|
528
852
|
/**
|
|
529
853
|
* Get the connector from the uri.
|
|
530
854
|
* @param id The id of the blob storage item in urn format.
|
|
@@ -541,53 +865,190 @@ class BlobStorageService {
|
|
|
541
865
|
}
|
|
542
866
|
return blobStorageModels.BlobStorageConnectorFactory.get(idUri.namespaceMethod());
|
|
543
867
|
}
|
|
868
|
+
/**
|
|
869
|
+
* Get an entity.
|
|
870
|
+
* @param id The id of the entity to get, or the index value if secondaryIndex is set.
|
|
871
|
+
* @param secondaryIndex Get the item using a secondary index.
|
|
872
|
+
* @param userIdentity The user identity to use with storage operations.
|
|
873
|
+
* @param nodeIdentity The node identity to use with storage operations.
|
|
874
|
+
* @returns The object if it can be found or throws.
|
|
875
|
+
* @internal
|
|
876
|
+
*/
|
|
877
|
+
async internalGet(id, userIdentity, nodeIdentity) {
|
|
878
|
+
const conditions = [];
|
|
879
|
+
if (this._includeUserIdentity) {
|
|
880
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
881
|
+
conditions.push({
|
|
882
|
+
property: "userIdentity",
|
|
883
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
884
|
+
value: userIdentity
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
if (this._includeNodeIdentity) {
|
|
888
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
889
|
+
conditions.push({
|
|
890
|
+
property: "nodeIdentity",
|
|
891
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
892
|
+
value: nodeIdentity
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
let entity$1;
|
|
896
|
+
if (conditions.length === 0) {
|
|
897
|
+
entity$1 = await this._entryEntityStorage.get(id);
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
const schema = this._entryEntityStorage.getSchema();
|
|
901
|
+
const primaryKey = entity.EntitySchemaHelper.getPrimaryKey(schema);
|
|
902
|
+
conditions.unshift({
|
|
903
|
+
property: primaryKey.property,
|
|
904
|
+
comparison: entity.ComparisonOperator.Equals,
|
|
905
|
+
value: id
|
|
906
|
+
});
|
|
907
|
+
const results = await this._entryEntityStorage.query({
|
|
908
|
+
conditions,
|
|
909
|
+
logicalOperator: entity.LogicalOperator.And
|
|
910
|
+
}, undefined, undefined, undefined, 1);
|
|
911
|
+
entity$1 = results.entities[0];
|
|
912
|
+
}
|
|
913
|
+
if (core.Is.empty(entity$1)) {
|
|
914
|
+
throw new core.NotFoundError(this.CLASS_NAME, "entityNotFound", id);
|
|
915
|
+
}
|
|
916
|
+
core.ObjectHelper.propertyDelete(entity$1, "nodeIdentity");
|
|
917
|
+
core.ObjectHelper.propertyDelete(entity$1, "userIdentity");
|
|
918
|
+
return entity$1;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Convert the entry to JSON-LD.
|
|
922
|
+
* @param entry The entry to convert.
|
|
923
|
+
* @param blob The optional blob to return.
|
|
924
|
+
* @returns The JSON-LD representation of the entry.
|
|
925
|
+
* @internal
|
|
926
|
+
*/
|
|
927
|
+
entryToJsonLd(entry, blob) {
|
|
928
|
+
const jsonLd = {
|
|
929
|
+
"@context": dataJsonLd.JsonLdProcessor.combineContexts([
|
|
930
|
+
blobStorageModels.BlobStorageContexts.ContextRoot,
|
|
931
|
+
blobStorageModels.BlobStorageContexts.ContextRootCommon,
|
|
932
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
933
|
+
], entry?.metadata?.["@context"]),
|
|
934
|
+
id: entry.id,
|
|
935
|
+
type: blobStorageModels.BlobStorageTypes.Entry,
|
|
936
|
+
dateCreated: entry.dateCreated,
|
|
937
|
+
dateModified: entry.dateModified,
|
|
938
|
+
blobSize: entry.blobSize,
|
|
939
|
+
blobHash: entry.blobHash,
|
|
940
|
+
encodingFormat: entry?.encodingFormat,
|
|
941
|
+
fileExtension: entry?.fileExtension,
|
|
942
|
+
metadata: entry?.metadata,
|
|
943
|
+
blob: core.Is.uint8Array(blob) ? core.Converter.bytesToBase64(blob) : undefined
|
|
944
|
+
};
|
|
945
|
+
return jsonLd;
|
|
946
|
+
}
|
|
544
947
|
}
|
|
545
948
|
|
|
546
949
|
/**
|
|
547
|
-
* Class representing
|
|
950
|
+
* Class representing entry for the blob storage.
|
|
548
951
|
*/
|
|
549
|
-
exports.
|
|
952
|
+
exports.BlobStorageEntry = class BlobStorageEntry {
|
|
550
953
|
/**
|
|
551
954
|
* The id for the blob.
|
|
552
955
|
*/
|
|
553
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;
|
|
554
973
|
/**
|
|
555
974
|
* The mime type for the blob.
|
|
556
975
|
*/
|
|
557
|
-
|
|
976
|
+
encodingFormat;
|
|
558
977
|
/**
|
|
559
978
|
* The extension.
|
|
560
979
|
*/
|
|
561
|
-
|
|
980
|
+
fileExtension;
|
|
562
981
|
/**
|
|
563
982
|
* The metadata for the blob as JSON-LD.
|
|
564
983
|
*/
|
|
565
984
|
metadata;
|
|
985
|
+
/**
|
|
986
|
+
* The user identity that created the blob.
|
|
987
|
+
*/
|
|
988
|
+
userIdentity;
|
|
989
|
+
/**
|
|
990
|
+
* The node identity that created the blob.
|
|
991
|
+
*/
|
|
992
|
+
nodeIdentity;
|
|
566
993
|
};
|
|
567
994
|
__decorate([
|
|
568
995
|
entity.property({ type: "string", isPrimary: true }),
|
|
569
996
|
__metadata("design:type", String)
|
|
570
|
-
], exports.
|
|
997
|
+
], exports.BlobStorageEntry.prototype, "id", void 0);
|
|
571
998
|
__decorate([
|
|
572
|
-
entity.property({ type: "string" }),
|
|
999
|
+
entity.property({ type: "string", format: "date-time", sortDirection: entity.SortDirection.Descending }),
|
|
1000
|
+
__metadata("design:type", String)
|
|
1001
|
+
], exports.BlobStorageEntry.prototype, "dateCreated", void 0);
|
|
1002
|
+
__decorate([
|
|
1003
|
+
entity.property({
|
|
1004
|
+
type: "string",
|
|
1005
|
+
format: "date-time",
|
|
1006
|
+
sortDirection: entity.SortDirection.Descending,
|
|
1007
|
+
optional: true
|
|
1008
|
+
}),
|
|
573
1009
|
__metadata("design:type", String)
|
|
574
|
-
], exports.
|
|
1010
|
+
], exports.BlobStorageEntry.prototype, "dateModified", void 0);
|
|
1011
|
+
__decorate([
|
|
1012
|
+
entity.property({ type: "number" }),
|
|
1013
|
+
__metadata("design:type", Number)
|
|
1014
|
+
], exports.BlobStorageEntry.prototype, "blobSize", void 0);
|
|
575
1015
|
__decorate([
|
|
576
1016
|
entity.property({ type: "string" }),
|
|
577
1017
|
__metadata("design:type", String)
|
|
578
|
-
], exports.
|
|
1018
|
+
], exports.BlobStorageEntry.prototype, "blobHash", void 0);
|
|
579
1019
|
__decorate([
|
|
580
|
-
entity.property({ type: "
|
|
1020
|
+
entity.property({ type: "string", optional: true }),
|
|
1021
|
+
__metadata("design:type", String)
|
|
1022
|
+
], exports.BlobStorageEntry.prototype, "encodingFormat", void 0);
|
|
1023
|
+
__decorate([
|
|
1024
|
+
entity.property({ type: "string", optional: true }),
|
|
1025
|
+
__metadata("design:type", String)
|
|
1026
|
+
], exports.BlobStorageEntry.prototype, "fileExtension", void 0);
|
|
1027
|
+
__decorate([
|
|
1028
|
+
entity.property({ type: "object", itemTypeRef: "IJsonLdNodeObject", optional: true }),
|
|
581
1029
|
__metadata("design:type", Object)
|
|
582
|
-
], exports.
|
|
583
|
-
|
|
1030
|
+
], exports.BlobStorageEntry.prototype, "metadata", void 0);
|
|
1031
|
+
__decorate([
|
|
1032
|
+
entity.property({ type: "string", optional: true }),
|
|
1033
|
+
__metadata("design:type", String)
|
|
1034
|
+
], exports.BlobStorageEntry.prototype, "userIdentity", void 0);
|
|
1035
|
+
__decorate([
|
|
1036
|
+
entity.property({ type: "string", optional: true }),
|
|
1037
|
+
__metadata("design:type", String)
|
|
1038
|
+
], exports.BlobStorageEntry.prototype, "nodeIdentity", void 0);
|
|
1039
|
+
exports.BlobStorageEntry = __decorate([
|
|
584
1040
|
entity.entity()
|
|
585
|
-
], exports.
|
|
1041
|
+
], exports.BlobStorageEntry);
|
|
586
1042
|
|
|
1043
|
+
/**
|
|
1044
|
+
* These are dummy entry points for the blob storage service.
|
|
1045
|
+
* In reality your application would create its own entry points based on the
|
|
1046
|
+
* blob types it wants to store, using a custom defaultBaseRoute.
|
|
1047
|
+
*/
|
|
587
1048
|
const restEntryPoints = [
|
|
588
1049
|
{
|
|
589
|
-
name: "
|
|
590
|
-
defaultBaseRoute: "blob",
|
|
1050
|
+
name: "blob-storage",
|
|
1051
|
+
defaultBaseRoute: "blob-storage",
|
|
591
1052
|
tags: tagsBlobStorage,
|
|
592
1053
|
generateRoutes: generateRestRoutesBlobStorage
|
|
593
1054
|
}
|
|
@@ -599,13 +1060,14 @@ const restEntryPoints = [
|
|
|
599
1060
|
* Initialize the schema for the blob storage entities.
|
|
600
1061
|
*/
|
|
601
1062
|
function initSchema() {
|
|
602
|
-
entity.EntitySchemaFactory.register("
|
|
1063
|
+
entity.EntitySchemaFactory.register("BlobStorageEntry", () => entity.EntitySchemaHelper.getSchema(exports.BlobStorageEntry));
|
|
603
1064
|
}
|
|
604
1065
|
|
|
605
1066
|
exports.BlobStorageService = BlobStorageService;
|
|
606
1067
|
exports.blobStorageCreate = blobStorageCreate;
|
|
607
1068
|
exports.blobStorageGet = blobStorageGet;
|
|
608
1069
|
exports.blobStorageGetContent = blobStorageGetContent;
|
|
1070
|
+
exports.blobStorageList = blobStorageList;
|
|
609
1071
|
exports.blobStorageRemove = blobStorageRemove;
|
|
610
1072
|
exports.blobStorageUpdate = blobStorageUpdate;
|
|
611
1073
|
exports.generateRestRoutesBlobStorage = generateRestRoutesBlobStorage;
|