# Gros fichiers

> Au-delà de DROP_MAX_SIZE_MB, le navigateur envoie le fichier directement au bucket, en morceaux, avec reprise. La règle CORS et le nettoyage qu’il faut.

Canonical: https://colis-docs.vercel.app/docs/gros-fichiers · Markdown: https://colis-docs.vercel.app/docs/gros-fichiers.md

Une fonction Vercel accepte au plus 4,5 Mo par requête. La page de livraison contourne cette limite
sans rien faire passer par la fonction : au-delà de `DROP_MAX_SIZE_MB` (4 par défaut), le navigateur
envoie le fichier lui-même au bucket, en morceaux, par des URL présignées. Le serveur ne fait que
signer et assembler. La taille maximale acceptée est `DROP_MAX_UPLOAD_MB`, 2 048 Mo par défaut.

## Comment ça se passe

1. `POST /api/transfers/uploads` avec `{ filename, size, contentType }` et les mêmes options que le
   formulaire (`expiresIn`, `passphrase`, `note`, `device`, `oneTime`). Le serveur tire un code, ouvre
   un envoi multipart sur la clé finale du colis, et garde le tout dans un enregistrement
   `meta/<code>.pending`. Il répond `{ code, uploadId, partSize, partCount }`.
2. `POST /api/transfers/uploads/:code/parts` avec `{ uploadId, partNumbers }` renvoie des URL `PUT`
   présignées pour ces morceaux (valables une heure, 50 au plus par appel), et les morceaux que le
   bucket a déjà. Chaque URL est signée avec la longueur exacte de son morceau.
3. Le navigateur envoie les morceaux au bucket, quatre à la fois, retente trois fois un morceau qui
   échoue, et lit l’en-tête `ETag` de chaque réponse.
4. `POST /api/transfers/uploads/:code/complete` avec `{ uploadId, parts: [{ partNumber, etag }] }`
   assemble le fichier, vérifie sa taille contre celle annoncée, puis fait exactement ce que fait
   `POST /api/transfers` : l’accusé, le jeton d’expéditeur, `parcel.sent`, et la même réponse `201`.
   Le colis ne se distingue plus d’un autre.
5. `DELETE /api/transfers/uploads/:code` avec `{ uploadId }` abandonne l’envoi.

Les morceaux font 8 Mio, davantage quand un fichier en demanderait plus de 10 000. Ces quatre routes
sont derrière `DROP_PASSWORD`, comme `POST /api/transfers`.

## La reprise

Le navigateur garde l’envoi en cours dans `localStorage`, sous le nom, la taille et la date de
modification du fichier. Si la connexion tombe ou si l’onglet se ferme, redéposez le même fichier : la
page propose **Reprendre l’envoi**, demande au bucket quels morceaux il a déjà, et envoie le reste.
**Annuler l’envoi** abandonne l’envoi dans le bucket et l’oublie.

## La règle CORS

Les morceaux vont du navigateur au bucket : le bucket doit autoriser `PUT` depuis l’adresse de votre
page, et laisser la page lire l’`ETag` de chaque réponse. Sans cette règle, les petits fichiers
continuent de passer, et un gros échoue avec un message qui renvoie ici.

Sur AWS S3, dans _Permissions → Cross-origin resource sharing (CORS)_ ; sur Cloudflare R2, dans
_R2 → votre bucket → Settings → CORS Policy_ :

```json
[
  {
    "AllowedOrigins": ["https://votre-livraison.vercel.app", "http://localhost:3400"],
    "AllowedMethods": ["PUT"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]
```

En ligne de commande, `aws s3api put-bucket-cors --bucket <bucket> --cors-configuration file://cors.json`
attend ce tableau enveloppé dans `{ "CORSRules": [ … ] }`, et pour R2,
`npx wrangler r2 bucket cors set <bucket> --file cors.json` attend sa propre forme :

```json
{
  "rules": [
    {
      "allowed": { "origins": ["https://votre-livraison.vercel.app"], "methods": ["PUT"], "headers": ["*"] },
      "exposeHeaders": ["ETag"],
      "maxAgeSeconds": 3600
    }
  ]
}
```

`colis verifier` avertit quand aucune règle n’autorise `PUT` en exposant `ETag`
(`Browser uploads (CORS)`).

## Le nettoyage

Les morceaux d’un envoi que personne n’a terminé restent stockés, et facturés, jusqu’à ce que quelque
chose les supprime. Ajoutez `AbortIncompleteMultipartUpload` après un jour à la règle de cycle de vie
du préfixe. R2 abandonne de lui-même les envois incomplets après sept jours, et accepte la même règle.

Sur AWS, les clés du déploiement ont besoin, en plus de `s3:PutObject`, `s3:GetObject` et
`s3:DeleteObject`, de `s3:AbortMultipartUpload` et `s3:ListMultipartUploadParts` pour abandonner et
reprendre un envoi.

## Ce qu’il faut savoir

- **La durée de vie démarre avec l’envoi.** L’expiration est écrite à l’ouverture de l’envoi : un
  envoi lent consomme une partie de la durée choisie. L’enregistrement en attente vit un jour, ou moins
  si le colis expire plus tôt.
- **La page et la CLI envoient en morceaux.** Au-delà de 4 Mo, `colis envoyer` passe par les mêmes
  routes que la page, sans règle CORS (elle ne concerne que les navigateurs). Le nœud n8n envoie en
  une seule requête, donc sous `DROP_MAX_SIZE_MB`.
- **Tout garder en une requête** : réglez `DROP_MAX_UPLOAD_MB` au niveau de `DROP_MAX_SIZE_MB`. Plus
  besoin de CORS, et un fichier trop gros est refusé avant l’envoi.

## Dans votre propre code

Les mêmes opérations existent dans `@colis/core`, pour construire un envoi direct ailleurs :
`createMultipartUpload()`, `presignUploadPart()`, `listUploadedParts()`,
`completeMultipartUpload()` et `abortMultipartUpload()`. Voir [API](https://colis-docs.vercel.app/docs/api#les-envois-en-morceaux).
