2.0 beta — new releases can include breaking changes. Stable 1.x docs
dimah-s3v2.0.0-beta.0

Multipart Hooks

Large-file multipart uploads — the server's part layout, part authorization, and assembly.

Enable multipart support on large-file routes by setting upload.multipart: true or passing a MultipartConfig object.

lib/s3.ts
import { dimahS3, route } from "@dimah-s3/server";
import { awsS3 } from "./aws-s3";

export const s3 = dimahS3({
  client: awsS3,
  bucket: process.env.S3_BUCKET!,
  routes: {
    video: route({
      upload: {
        fileTypes: ["video/*"],
        maxFileSize: 500 * 1024 * 1024, // 500MB
        multipart: true, 
        onConfirmed: async ({ key, object }) => {
          // Runs once multipart complete has verified the object
        },
      },
    }),
  },
});

Multipart lifecycle flow

Multipart upload flow
  1. upload.guardInit
  2. CreateMultipartUploadS3
  3. onStarthook
  4. multipart.guardEach part, list, complete, abort
  5. CompleteMultipartUploadS3
  6. confirmGuardhook
  7. onConfirmedhook
  1. Init runs upload.object, picks the part layout, runs upload.guard, creates the multipart upload, and runs upload.onStart (kind: "multipart"). If onStart throws, the upload is aborted. The response has the uploadId, the upload ticket, partSize, partCount, and whether parts need a checksum.
  2. Sign part runs multipart.guard with action: "part" and signs a PUT URL for exactly that part's size.
  3. List parts (action: "list") returns the parts S3 already has, so a client can resume.
  4. Complete (action: "complete") checks every part, assembles the object, reads it with HeadObject, and runs confirmGuard and onConfirmed, the same as a single-shot confirm.
  5. Abort (action: "abort") aborts the upload and runs multipart.onAbort. Like delete, it is idempotent: an upload that is already gone still succeeds and runs onAbort. An upload that was completed fails with 409 CONFLICT.

Every call after init sends only the ticket. The route guard runs on each one.


Part layout

The server picks the layout at init from the declared size, and the client follows it. Init does not accept a part size.

  • partSize starts at upload.multipart.partSize (8 MiB by default).
  • It grows when the file would need more than 10,000 parts, is rounded up to a whole MiB, and stays between 5 MiB and 5 GiB.
  • Every part except the last is exactly partSize. The last one holds the rest.
  • Files over 5 TiB return FILE_TOO_LARGE.

Sign part rejects a part number outside 1..partCount with MULTIPART_PART_INVALID, and never calls ListParts. Complete reads every ListParts page and checks:

  • parts 1..partCount are all present, otherwise MULTIPART_PART_MISSING;
  • each part has exactly its layout size, otherwise UPLOAD_SIZE_MISMATCH;
  • with checksum on, each part has a SHA-256, otherwise CHECKSUM_REQUIRED.

Part checksums

With upload.checksum (or verifyContent) on, every part must send its SHA-256 to sign part, and the server signs it into the part URL. S3 rejects a part whose bytes do not match. The React client hashes each part as it streams.

Retries

Complete is safe to retry. When an earlier call already completed the upload, the stored object is verified and the hooks run again, as long as it carries this upload's marker. Like confirm, onConfirmed runs at least once: dedupe on uploadToken.


Ticket lifetime

A multipart ticket is valid for upload.multipart.ticketExpiresIn seconds, one day by default. After that, every call returns UPLOAD_TICKET_EXPIRED, except abort, which accepts the ticket for 7 more days.

upload: {
  multipart: {
    partSize: 16 * 1024 * 1024, 
    ticketExpiresIn: 6 * 60 * 60, 
  },
},

Add an S3 lifecycle rule that aborts incomplete multipart uploads, so parts of uploads nobody completes or aborts do not stay in the bucket.


Type reference

import type {
  MultipartConfig,
  MultipartGuardContext,
  MultipartOnAbortContext,
  MultipartUploadContext,
} from "@dimah-s3/server";

MultipartConfig

Prop

Type


MultipartUploadContext

Shared by multipart.guard and multipart.onAbort. Init uses UploadGuardContext and UploadOnStartContext from Upload Hooks.

Prop

Type


MultipartGuardContext

Prop

Type


MultipartOnAbortContext

Prop

Type

Frequently asked questions

On this page