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