Skip to content

Commit 56700d6

Browse files
committed
Allow multipart uploads of large files
Change-type: minor
1 parent ea059b0 commit 56700d6

File tree

7 files changed

+868
-4
lines changed

7 files changed

+868
-4
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"webpack-build": "npm run webpack-browser && npm run webpack-module && npm run webpack-server",
2121
"lint": "balena-lint -t tsconfig.dev.json -e js -e ts src test build typings Gruntfile.cts && npx tsc --project tsconfig.dev.json --noEmit",
2222
"test": "npm run build && npm run lint && npm run webpack-build && npm run test:compose && npm run test:generated-types",
23-
"test:compose": "trap 'docker compose -f docker-compose.npm-test.yml down ; echo Stopped ; exit 0' INT; docker compose -f docker-compose.npm-test.yml up -d && sleep 2 && DATABASE_URL=postgres://docker:docker@localhost:5431/postgres PINEJS_WEBRESOURCE_MAXFILESIZE=1000000000 S3_ENDPOINT=http://localhost:43680 S3_ACCESS_KEY=USERNAME S3_SECRET_KEY=PASSWORD S3_STORAGE_ADAPTER_BUCKET=balena-pine-web-resources S3_REGION=us-east-1 PINEJS_QUEUE_CONCURRENCY=1 TZ=UTC npx mocha",
23+
"test:compose": "trap 'docker compose -f docker-compose.npm-test.yml down ; echo Stopped ; exit 0' INT; docker compose -f docker-compose.npm-test.yml up -d && sleep 2 && DATABASE_URL=postgres://docker:docker@localhost:5431/postgres PINEJS_WEBRESOURCE_MAXFILESIZE=1000000000 S3_ENDPOINT=http://localhost:43680 S3_ACCESS_KEY=USERNAME S3_SECRET_KEY=PASSWORD S3_STORAGE_ADAPTER_BUCKET=balena-pine-web-resources S3_REGION=us-east-1 PINEJS_QUEUE_CONCURRENCY=1 TZ=UTC PINEJS_WEBRESOURCE_MULTIPART_ENABLED=true npx mocha",
2424
"test:generated-types": "npm run generate-types && git diff --exit-code ./src/sbvr-api/user.ts ./src/migrator/migrations.ts ./src/sbvr-api/dev.ts",
2525
"lint-fix": "balena-lint -t tsconfig.dev.json -e js -e ts --fix src test build typings Gruntfile.cts",
2626
"generate-types": "node ./bin/sbvr-compiler.js generate-types ./src/sbvr-api/user.sbvr ./src/sbvr-api/user.ts && node ./bin/sbvr-compiler.js generate-types ./src/migrator/migrations.sbvr ./src/migrator/migrations.ts && node ./bin/sbvr-compiler.js generate-types ./src/sbvr-api/dev.sbvr ./src/sbvr-api/dev.ts && node ./bin/sbvr-compiler.js generate-types ./src/tasks/tasks.sbvr ./src/tasks/tasks.ts && node ./bin/sbvr-compiler.js generate-types ./src/webresource-handler/webresource.sbvr ./src/webresource-handler/webresource.ts && balena-lint -t tsconfig.dev.json --fix ./src/sbvr-api/user.ts ./src/migrator/migrations.ts ./src/sbvr-api/dev.ts"
@@ -70,7 +70,7 @@
7070
"devDependencies": {
7171
"@balena/lint": "^9.1.6",
7272
"@balena/pinejs": "file:./",
73-
"@balena/pinejs-webresource-s3": "^1.0.4",
73+
"@balena/pinejs-webresource-s3": "2.0.0-build-new-multiparthandle-interface-66b03581234eaa7ce15c6f389e39b5b7ed3d1bc5-1",
7474
"@faker-js/faker": "^9.6.0",
7575
"@types/busboy": "^1.5.4",
7676
"@types/chai": "^5.2.1",
@@ -145,7 +145,7 @@
145145
],
146146
"loader": "ts-node/esm/transpile-only",
147147
"exit": true,
148-
"timeout": 60000,
148+
"timeout": 6000000,
149149
"recursive": true
150150
},
151151
"versionist": {

src/config-loader/env.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,17 @@ export const tasks = {
159159
queueIntervalMS: intVar('PINEJS_QUEUE_INTERVAL_MS', 1000),
160160
};
161161

162+
export const webResource = {
163+
multipartUploadEnabled: boolVar(
164+
'PINEJS_WEBRESOURCE_MULTIPART_ENABLED',
165+
false,
166+
),
167+
singleUploadMaxFilesize: intVar(
168+
'PINEJS_WEBRESOURCE_MAXFILESIZE',
169+
299 * 1024 * 1024,
170+
),
171+
};
172+
162173
export const guardTestMockOnly = () => {
163174
if (process.env.DEPLOYMENT !== 'TEST') {
164175
throw new Error('Attempting to use TEST_MOCK_ONLY outside of tests');

src/sbvr-api/sbvr-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ const getFinalAbstractSqlModel = (
11401140
return (request.finalAbstractSqlModel ??= models[finalModel].abstractSql);
11411141
};
11421142

1143-
const getIdField = (
1143+
export const getIdField = (
11441144
request: Pick<
11451145
uriParser.ODataRequest,
11461146
| 'translateVersions'

src/webresource-handler/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ import { TypedError } from 'typed-error';
1818
import type { Resolvable } from '../sbvr-api/common-types.js';
1919
import type WebresourceModel from './webresource.js';
2020
import { importSBVR } from '../server-glue/sbvr-loader.js';
21+
import {
22+
isMultipartUploadAvailable,
23+
multipartUploadHooks,
24+
} from './multipartUpload.js';
2125

2226
export * from './handlers/index.js';
27+
export type { BeginUploadResponse } from './multipartUpload.js';
2328

2429
export interface IncomingFile {
2530
fieldname: string;
@@ -332,6 +337,10 @@ const throwIfWebresourceNotInMultipart = (
332337
{ req, request }: HookArgs,
333338
) => {
334339
if (
340+
request.custom.isAction !== 'beginUpload' &&
341+
request.custom.isAction !== 'commitUpload' &&
342+
request.custom.isAction !== 'cancelUpload' &&
343+
req.user !== permissions.root.user &&
335344
!req.is?.('multipart') &&
336345
webResourceFields.some((field) => request.values[field] != null)
337346
) {
@@ -528,6 +537,15 @@ export const setupUploadHooks = (
528537
resourceName,
529538
getCreateWebResourceHooks(handler),
530539
);
540+
541+
if (isMultipartUploadAvailable(handler)) {
542+
sbvrUtils.addPureHook(
543+
'POST',
544+
apiRoot,
545+
resourceName,
546+
multipartUploadHooks(handler),
547+
);
548+
}
531549
};
532550

533551
const initSql = `

0 commit comments

Comments
 (0)