@balena/pinejs 17.0.0-build-wip-large-file-uploads-8d9c57891b422476172efba74cacc2a0fea09248-1 → 17.0.0-build-v17-13acf75c74cc64a383aca6e91ba9582f40f60ea1-2

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,27 +6,17 @@ import {
6
6
  WebResourceError,
7
7
  type WebResourceHandler,
8
8
  } from '..';
9
- import type {
10
- BeginUploadHandlerResponse,
11
- BeginUploadPayload,
12
- CommitUploadHandlerPayload,
13
- UploadUrl,
14
- } from '../multipartUpload';
15
9
  import {
16
10
  S3Client,
17
11
  type S3ClientConfig,
18
12
  DeleteObjectCommand,
19
13
  type PutObjectCommandInput,
20
14
  GetObjectCommand,
21
- CreateMultipartUploadCommand,
22
- UploadPartCommand,
23
- CompleteMultipartUploadCommand,
24
- HeadObjectCommand,
25
15
  } from '@aws-sdk/client-s3';
26
16
  import { Upload } from '@aws-sdk/lib-storage';
27
17
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
28
18
 
29
- import { randomUUID } from 'node:crypto';
19
+ import { randomUUID } from 'crypto';
30
20
  import type { WebResourceType as WebResource } from '@balena/sbvr-types';
31
21
  import memoize from 'memoizee';
32
22
 
@@ -81,7 +71,9 @@ export class S3Handler implements WebResourceHandler {
81
71
 
82
72
  public async handleFile(resource: IncomingFile): Promise<UploadResponse> {
83
73
  let size = 0;
84
- const key = this.getFileKey(resource.fieldname, resource.originalname);
74
+ const key = `${resource.fieldname}_${randomUUID()}_${
75
+ resource.originalname
76
+ }`;
85
77
  const params: PutObjectCommandInput = {
86
78
  Bucket: this.bucket,
87
79
  Key: key,
@@ -130,62 +122,6 @@ export class S3Handler implements WebResourceHandler {
130
122
  return webResource;
131
123
  }
132
124
 
133
- public async beginUpload(
134
- fieldName: string,
135
- payload: BeginUploadPayload,
136
- ): Promise<BeginUploadHandlerResponse> {
137
- const fileKey = this.getFileKey(fieldName, payload.filename);
138
-
139
- const createMultiPartResponse = await this.client.send(
140
- new CreateMultipartUploadCommand({
141
- Bucket: this.bucket,
142
- Key: fileKey,
143
- ContentType: payload.content_type,
144
- }),
145
- );
146
-
147
- if (createMultiPartResponse.UploadId == null) {
148
- throw new WebResourceError('Failed to create multipart upload.');
149
- }
150
-
151
- const uploadUrls = await this.getPartUploadUrls(
152
- fileKey,
153
- createMultiPartResponse.UploadId,
154
- payload,
155
- );
156
- return { fileKey, uploadId: createMultiPartResponse.UploadId, uploadUrls };
157
- }
158
-
159
- public async commitUpload({
160
- fileKey,
161
- uploadId,
162
- filename,
163
- multipartUploadChecksums,
164
- }: CommitUploadHandlerPayload): Promise<WebResource> {
165
- await this.client.send(
166
- new CompleteMultipartUploadCommand({
167
- Bucket: this.bucket,
168
- Key: fileKey,
169
- UploadId: uploadId,
170
- MultipartUpload: multipartUploadChecksums,
171
- }),
172
- );
173
-
174
- const headResult = await this.client.send(
175
- new HeadObjectCommand({
176
- Bucket: this.bucket,
177
- Key: fileKey,
178
- }),
179
- );
180
-
181
- return {
182
- href: this.getS3URL(fileKey),
183
- filename: filename,
184
- size: headResult.ContentLength,
185
- content_type: headResult.ContentType,
186
- };
187
- }
188
-
189
125
  private s3SignUrl(fileKey: string): Promise<string> {
190
126
  const command = new GetObjectCommand({
191
127
  Bucket: this.bucket,
@@ -200,70 +136,8 @@ export class S3Handler implements WebResourceHandler {
200
136
  return `${this.config.endpoint}/${this.bucket}/${key}`;
201
137
  }
202
138
 
203
- private getFileKey(fieldName: string, fileName: string) {
204
- return `${fieldName}_${randomUUID()}_${fileName}`;
205
- }
206
-
207
139
  private getKeyFromHref(href: string): string {
208
140
  const hrefWithoutParams = normalizeHref(href);
209
141
  return hrefWithoutParams.substring(hrefWithoutParams.lastIndexOf('/') + 1);
210
142
  }
211
-
212
- private async getPartUploadUrls(
213
- fileKey: string,
214
- uploadId: string,
215
- payload: BeginUploadPayload,
216
- ): Promise<UploadUrl[]> {
217
- const chunkSizesWithParts = await this.getChunkSizesWithParts(
218
- payload.size,
219
- payload.chunk_size,
220
- );
221
- return Promise.all(
222
- chunkSizesWithParts.map(async ({ chunkSize, partNumber }) => ({
223
- chunkSize,
224
- partNumber,
225
- url: await this.getPartUploadUrl(
226
- fileKey,
227
- uploadId,
228
- partNumber,
229
- chunkSize,
230
- ),
231
- })),
232
- );
233
- }
234
-
235
- private async getPartUploadUrl(
236
- fileKey: string,
237
- uploadId: string,
238
- partNumber: number,
239
- partSize: number,
240
- ): Promise<string> {
241
- const command = new UploadPartCommand({
242
- Bucket: this.bucket,
243
- Key: fileKey,
244
- UploadId: uploadId,
245
- PartNumber: partNumber,
246
- ContentLength: partSize,
247
- });
248
-
249
- return getSignedUrl(this.client, command, {
250
- expiresIn: this.signedUrlExpireTimeSeconds,
251
- });
252
- }
253
-
254
- private async getChunkSizesWithParts(
255
- size: number,
256
- chunkSize: number,
257
- ): Promise<Array<Pick<UploadUrl, 'chunkSize' | 'partNumber'>>> {
258
- const chunkSizesWithParts = [];
259
- let partNumber = 1;
260
- let remainingSize = size;
261
- while (remainingSize > 0) {
262
- const currentChunkSize = Math.min(remainingSize, chunkSize);
263
- chunkSizesWithParts.push({ chunkSize: currentChunkSize, partNumber });
264
- remainingSize -= currentChunkSize;
265
- partNumber += 1;
266
- }
267
- return chunkSizesWithParts;
268
- }
269
143
  }
@@ -1,25 +1,19 @@
1
+ import type * as Express from 'express';
2
+ import busboy from 'busboy';
3
+ import type * as stream from 'node:stream';
4
+ import * as uriParser from '../sbvr-api/uri-parser';
5
+ import * as sbvrUtils from '../sbvr-api/sbvr-utils';
6
+ import type { HookArgs } from '../sbvr-api/hooks';
7
+ import { getApiRoot, getModel } from '../sbvr-api/sbvr-utils';
8
+ import { checkPermissions } from '../sbvr-api/permissions';
9
+ import { NoopHandler } from './handlers/NoopHandler';
1
10
  import {
2
11
  odataNameToSqlName,
3
12
  sqlNameToODataName,
4
13
  } from '@balena/odata-to-abstract-sql';
14
+ import { errors, permissions } from '../server-glue/module';
5
15
  import type { WebResourceType as WebResource } from '@balena/sbvr-types';
6
- import busboy from 'busboy';
7
- import type * as Express from 'express';
8
- import type * as stream from 'node:stream';
9
16
  import { TypedError } from 'typed-error';
10
- import type { HookArgs } from '../sbvr-api/hooks';
11
- import { checkPermissions } from '../sbvr-api/permissions';
12
- import * as sbvrUtils from '../sbvr-api/sbvr-utils';
13
- import { getApiRoot, getModel } from '../sbvr-api/sbvr-utils';
14
- import * as uriParser from '../sbvr-api/uri-parser';
15
- import { errors, permissions } from '../server-glue/module';
16
- import { NoopHandler } from './handlers/NoopHandler';
17
- import type {
18
- BeginUploadHandlerResponse,
19
- BeginUploadPayload,
20
- CommitUploadHandlerPayload,
21
- } from './multipartUpload';
22
- import { multipartUploadHooks } from './multipartUpload';
23
17
 
24
18
  export * from './handlers';
25
19
 
@@ -40,14 +34,6 @@ export interface WebResourceHandler {
40
34
  handleFile: (resource: IncomingFile) => Promise<UploadResponse>;
41
35
  removeFile: (fileReference: string) => Promise<void>;
42
36
  onPreRespond: (webResource: WebResource) => Promise<WebResource>;
43
-
44
- beginUpload: (
45
- fieldName: string,
46
- payload: BeginUploadPayload,
47
- ) => Promise<BeginUploadHandlerResponse>;
48
- commitUpload: (
49
- commitInfo: CommitUploadHandlerPayload,
50
- ) => Promise<WebResource>;
51
37
  }
52
38
 
53
39
  export class WebResourceError extends TypedError {}
@@ -230,7 +216,7 @@ export const getUploaderMiddlware = (
230
216
  };
231
217
  };
232
218
 
233
- export const getWebResourceFields = (
219
+ const getWebResourceFields = (
234
220
  request: uriParser.ODataRequest,
235
221
  useTranslations = true,
236
222
  ): string[] => {
@@ -263,8 +249,6 @@ const throwIfWebresourceNotInMultipart = (
263
249
  { req, request }: HookArgs,
264
250
  ) => {
265
251
  if (
266
- request.custom.isAction !== 'beginUpload' &&
267
- request.custom.isAction !== 'commitUpload' &&
268
252
  !req.is?.('multipart') &&
269
253
  webResourceFields.some((field) => request.values[field] != null)
270
254
  ) {
@@ -463,23 +447,4 @@ export const setupUploadHooks = (
463
447
  resourceName,
464
448
  getCreateWebResourceHooks(handler),
465
449
  );
466
-
467
- sbvrUtils.addPureHook(
468
- 'POST',
469
- apiRoot,
470
- resourceName,
471
- multipartUploadHooks(handler),
472
- );
473
- };
474
-
475
- // eslint-disable-next-line @typescript-eslint/no-var-requires
476
- const webresourceModel: string = require('./webresource.sbvr');
477
- export const config = {
478
- models: [
479
- {
480
- apiRoot: 'webresource',
481
- modelText: webresourceModel,
482
- modelName: 'webresource',
483
- },
484
- ] as sbvrUtils.ExecutableModel[],
485
450
  };
@@ -1,39 +0,0 @@
1
- import type { AnyObject } from 'pinejs-client-core';
2
- import type { WebResourceHandler } from '.';
3
- import type { ODataRequest } from '../sbvr-api/uri-parser';
4
- import { sbvrUtils } from '../server-glue/module';
5
- export interface BeginUploadPayload {
6
- filename: string;
7
- content_type: string;
8
- size: number;
9
- chunk_size: number;
10
- }
11
- export interface UploadUrl {
12
- url: string;
13
- chunkSize: number;
14
- partNumber: number;
15
- }
16
- export interface BeginUploadHandlerResponse {
17
- uploadUrls: UploadUrl[];
18
- fileKey: string;
19
- uploadId: string;
20
- }
21
- export interface PendingUpload extends BeginUploadPayload {
22
- fieldName: string;
23
- fileKey: string;
24
- uploadId: string;
25
- }
26
- export interface BeginUploadResponse {
27
- [fieldName: string]: {
28
- key: string;
29
- uploadUrls: UploadUrl[];
30
- };
31
- }
32
- export interface CommitUploadHandlerPayload {
33
- fileKey: string;
34
- uploadId: string;
35
- filename: string;
36
- multipartUploadChecksums?: AnyObject;
37
- }
38
- export declare const multipartUploadHooks: (webResourceHandler: WebResourceHandler) => sbvrUtils.Hooks;
39
- export declare const beginUpload: (webResourceHandler: WebResourceHandler, odataRequest: ODataRequest, actorId?: number) => Promise<BeginUploadResponse>;
@@ -1,187 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.beginUpload = exports.multipartUploadHooks = void 0;
4
- const node_crypto_1 = require("node:crypto");
5
- const _1 = require(".");
6
- const sbvr_utils_1 = require("../sbvr-api/sbvr-utils");
7
- const module_1 = require("../server-glue/module");
8
- const MB = 1024 * 1024;
9
- const multipartUploadHooks = (webResourceHandler) => {
10
- return {
11
- POSTPARSE: async ({ req, request, tx, api: vocabularyApi }) => {
12
- if (request.odataQuery.property?.resource === 'beginUpload') {
13
- const uploadParams = parseBeginUpload(request);
14
- await vocabularyApi.post({
15
- url: request.url.substring(1).replace('beginUpload', 'canAccess'),
16
- body: { method: 'PATCH' },
17
- });
18
- tx = await module_1.sbvrUtils.db.transaction();
19
- req.tx = tx;
20
- request.tx = tx;
21
- request.method = 'PATCH';
22
- request.values = uploadParams;
23
- request.odataQuery.resource = request.resourceName;
24
- delete request.odataQuery.property;
25
- request.custom.isAction = 'beginUpload';
26
- }
27
- else if (request.odataQuery.property?.resource === 'commitUpload') {
28
- const commitPayload = await parseCommitUpload(request);
29
- await vocabularyApi.post({
30
- url: request.url.substring(1).replace('commitUpload', 'canAccess'),
31
- body: { method: 'PATCH' },
32
- });
33
- const webresource = await webResourceHandler.commitUpload({
34
- fileKey: commitPayload.metadata.fileKey,
35
- uploadId: commitPayload.metadata.uploadId,
36
- filename: commitPayload.metadata.filename,
37
- multipartUploadChecksums: commitPayload.additionalCommitInfo,
38
- });
39
- await sbvr_utils_1.api.webresource.patch({
40
- resource: 'multipart_upload',
41
- body: {
42
- status: 'completed',
43
- },
44
- options: {
45
- $filter: {
46
- uuid: commitPayload.key,
47
- },
48
- },
49
- passthrough: {
50
- req: module_1.permissions.root,
51
- tx: tx,
52
- },
53
- });
54
- request.method = 'PATCH';
55
- request.values = {
56
- [commitPayload.metadata.fieldName]: webresource,
57
- };
58
- request.odataQuery.resource = request.resourceName;
59
- delete request.odataQuery.property;
60
- request.custom.isAction = 'commitUpload';
61
- request.custom.commitUploadPayload = webresource;
62
- }
63
- },
64
- PRERESPOND: async ({ req, request, response, tx }) => {
65
- if (request.custom.isAction === 'beginUpload') {
66
- await tx.rollback();
67
- response.statusCode = 200;
68
- response.body = await (0, exports.beginUpload)(webResourceHandler, request, req.user?.actor);
69
- }
70
- else if (request.custom.isAction === 'commitUpload') {
71
- response.body = await webResourceHandler.onPreRespond(request.custom.commitUploadPayload);
72
- }
73
- },
74
- };
75
- };
76
- exports.multipartUploadHooks = multipartUploadHooks;
77
- const beginUpload = async (webResourceHandler, odataRequest, actorId) => {
78
- const payload = odataRequest.values;
79
- const fieldName = Object.keys(payload)[0];
80
- const metadata = payload[fieldName];
81
- const { fileKey, uploadId, uploadUrls } = await webResourceHandler.beginUpload(fieldName, metadata);
82
- const uuid = (0, node_crypto_1.randomUUID)();
83
- try {
84
- await sbvr_utils_1.api.webresource.post({
85
- resource: 'multipart_upload',
86
- body: {
87
- uuid,
88
- resource_name: odataRequest.resourceName,
89
- field_name: fieldName,
90
- resource_id: odataRequest.affectedIds?.[0],
91
- upload_id: uploadId,
92
- file_key: fileKey,
93
- status: 'pending',
94
- filename: metadata.filename,
95
- content_type: metadata.content_type,
96
- size: metadata.size,
97
- chunk_size: metadata.chunk_size,
98
- expiry_date: Date.now() + 7 * 24 * 60 * 60 * 1000,
99
- is_created_by__actor: actorId,
100
- },
101
- passthrough: {
102
- req: module_1.permissions.root,
103
- },
104
- });
105
- }
106
- catch (err) {
107
- console.error('failed to start multipart upload', err);
108
- throw new module_1.errors.BadRequestError('Failed to start multipart upload');
109
- }
110
- return { [fieldName]: { key: uuid, uploadUrls } };
111
- };
112
- exports.beginUpload = beginUpload;
113
- const parseBeginUpload = (request) => {
114
- if (request.odataQuery.key == null) {
115
- throw new module_1.errors.BadRequestError();
116
- }
117
- const fieldNames = Object.keys(request.values);
118
- if (fieldNames.length !== 1) {
119
- throw new module_1.errors.BadRequestError('You can only get upload url for one field at a time');
120
- }
121
- const [fieldName] = fieldNames;
122
- const webResourceFields = (0, _1.getWebResourceFields)(request, false);
123
- if (!webResourceFields.includes(fieldName)) {
124
- throw new module_1.errors.BadRequestError(`You must provide a valid webresource field from: ${JSON.stringify(webResourceFields)}`);
125
- }
126
- const beginUploadPayload = parseBeginUploadPayload(request.values[fieldName]);
127
- if (beginUploadPayload == null) {
128
- throw new module_1.errors.BadRequestError('Invalid file metadata');
129
- }
130
- const uploadMetadataCheck = {
131
- ...beginUploadPayload,
132
- href: 'metadata_check',
133
- };
134
- return { [fieldName]: uploadMetadataCheck };
135
- };
136
- const parseBeginUploadPayload = (payload) => {
137
- if (typeof payload !== 'object') {
138
- return null;
139
- }
140
- let { filename, content_type, size, chunk_size } = payload;
141
- if (typeof filename !== 'string' ||
142
- typeof content_type !== 'string' ||
143
- typeof size !== 'number' ||
144
- (chunk_size != null && typeof chunk_size !== 'number') ||
145
- (chunk_size != null && chunk_size < 5 * MB)) {
146
- return null;
147
- }
148
- if (chunk_size == null) {
149
- chunk_size = 5 * MB;
150
- }
151
- return { filename, content_type, size, chunk_size };
152
- };
153
- const parseCommitUpload = async (request) => {
154
- if (request.odataQuery.key == null) {
155
- throw new module_1.errors.BadRequestError();
156
- }
157
- const { key, additionalCommitInfo } = request.values;
158
- if (typeof key !== 'string') {
159
- throw new module_1.errors.BadRequestError('Invalid key type');
160
- }
161
- const [multipartUpload] = (await sbvr_utils_1.api.webresource.get({
162
- resource: 'multipart_upload',
163
- options: {
164
- $select: ['id', 'file_key', 'upload_id', 'field_name', 'filename'],
165
- $filter: {
166
- uuid: key,
167
- status: 'pending',
168
- expiry_date: { $gt: { $now: {} } },
169
- },
170
- },
171
- passthrough: {
172
- req: module_1.permissions.root,
173
- tx: request.tx,
174
- },
175
- }));
176
- if (multipartUpload == null) {
177
- throw new module_1.errors.BadRequestError(`Invalid upload for key ${key}`);
178
- }
179
- const metadata = {
180
- fileKey: multipartUpload.file_key,
181
- uploadId: multipartUpload.upload_id,
182
- filename: multipartUpload.filename,
183
- fieldName: multipartUpload.field_name,
184
- };
185
- return { key, additionalCommitInfo, metadata };
186
- };
187
- //# sourceMappingURL=multipartUpload.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multipartUpload.js","sourceRoot":"","sources":["../../src/webresource-handler/multipartUpload.ts"],"names":[],"mappings":"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"}
@@ -1,63 +0,0 @@
1
- Vocabulary: Auth
2
-
3
- Term: actor
4
- Term: expiry date
5
- Concept Type: Date Time (Type)
6
-
7
- Vocabulary: webresource
8
-
9
- Term: uuid
10
- Concept Type: Short Text (Type)
11
- Term: resource name
12
- Concept Type: Short Text (Type)
13
- Term: field name
14
- Concept Type: Short Text (Type)
15
- Term: resource id
16
- Concept Type: Integer (Type)
17
- Term: upload id
18
- Concept Type: Short Text (Type)
19
- Term: file key
20
- Concept Type: Short Text (Type)
21
- Term: status
22
- Concept Type: Short Text (Type)
23
- Term: filename
24
- Concept Type: Short Text (Type)
25
- Term: content type
26
- Concept Type: Short Text (Type)
27
- Term: size
28
- Concept Type: Integer (Type)
29
- Term: chunk size
30
- Concept Type: Integer (Type)
31
- Term: valid until date
32
- Concept Type: Date Time (Type)
33
-
34
- Term: multipart upload
35
- Fact type: multipart upload has uuid
36
- Necessity: each multipart upload has exactly one uuid
37
- Necessity: each uuid is of exactly one multipart upload
38
- Fact type: multipart upload has resource name
39
- Necessity: each multipart upload has exactly one resource name
40
- Fact type: multipart upload has field name
41
- Necessity: each multipart upload has exactly one field name
42
- Fact type: multipart upload has resource id
43
- Necessity: each multipart upload has exactly one resource id
44
- Fact type: multipart upload has upload id
45
- Necessity: each multipart upload has exactly one upload id
46
- Fact type: multipart upload has file key
47
- Necessity: each multipart upload has exactly one file key
48
- Fact type: multipart upload has status
49
- Necessity: each multipart upload has exactly one status
50
- Definition: "pending" or "completed" or "cancelled"
51
- Fact type: multipart upload has filename
52
- Necessity: each multipart upload has exactly one filename
53
- Fact type: multipart upload has content type
54
- Necessity: each multipart upload has exactly one content type
55
- Fact type: multipart upload has size
56
- Necessity: each multipart upload has exactly one size
57
- Fact type: multipart upload has chunk size
58
- Necessity: each multipart upload has exactly one chunk size
59
- Fact type: multipart upload has expiry date (Auth)
60
- Necessity: each multipart upload has exactly one expiry date (Auth)
61
- Fact type: multipart upload is created by actor (Auth)
62
- Necessity: each multipart upload is created by at most one actor (Auth)
63
- Reference Type: informative