colisdocs

API / Bibliothèque

@colis/core : createBucket, l’API fichiers, les envois en morceaux, les enregistrements JSON, les codes et le gestionnaire de routes.

@colis/core est le seul paquet qui détient les identifiants du stockage. La page de livraison est construite dessus ; vous pouvez l’utiliser pour construire votre propre flux. Il tourne côté serveur uniquement.

createBucket(config?)

Renvoie un Bucket. L’appel est léger : le S3Client sous-jacent n’est construit qu’à la première requête, donc on peut l’appeler au niveau du module. Chaque option est dans Configuration.

import { createBucket } from '@colis/core'

const store = createBucket({ bucket: 'livraisons', prefix: 'drop' })

new Bucket(config) est équivalent, et exporté pour typer ou étendre.

L’API fichiers

upload(body, options?)

Envoie un corps en un seul PutObject. Écrire sur une clé existante la remplace.

body accepte string, Buffer, Uint8Array, ArrayBuffer, tableau typé, Blob, File, Readable de Node ou ReadableStream web.

OptionDéfaut
keygénérée : <uuid>-<filename>
prefixle préfixe du bucket
filenamele nom du File, s’il y en a un
contentTypele type du File, sinon deviné par l’extension, sinon application/octet-stream
contentLengthla taille du corps ; obligatoire pour un flux
cacheControl, contentDisposition, metadata—
acl— (la plupart des buckets refusent les ACL)
ifMatch— n’écrire que si l’ETag stocké correspond encore
ifAbsent— n’écrire que si rien n’est encore stocké
signal—

Renvoie { bucket, key, path, contentType, size?, etag?, url? }. key est la poignée à repasser aux autres méthodes, path la clé réelle dans le bucket, préfixe compris ; url n’existe que si publicUrl est configuré.

put(id, body, options?)

upload(body, { key: id }), avec l’identifiant en premier. Mêmes options sauf key, même résultat.

get(key, options?)

Relit un fichier, ou null si la clé n’existe pas. Le résultat porte contentType, filename, size, etag, lastModified, metadata, et le corps : body (un Readable), bytes() ou text(), à lire une seule fois.

head(key, options?)

Ce que S3 sait d’un objet sans le télécharger, ou null. Les mêmes champs que get(), sans le corps.

getUrl(key, options?)

L’adresse publique si publicUrl est configuré, une URL GET présignée sinon. La signature est un calcul local : ni aller-retour réseau, ni permission supplémentaire.

OptionDéfaut
expiresIn3600 secondes, au plus 604800
signedtrue sauf si publicUrl est configuré
download— Content-Disposition: attachment, avec un nom de fichier si vous passez une chaîne

delete(key)

Supprime une clé ou un tableau de clés (par lots de 1 000). Supprimer une clé absente n’est pas une erreur ; un échec par clé signalé par S3 lève DELETE_FAILED en les nommant.

Les envois en morceaux

Pour envoyer un gros fichier du navigateur directement au bucket, comme le fait la page de livraison (voir Gros fichiers) :

const { uploadId } = await store.createMultipartUpload(key, { filename, contentType })

// Pour chaque morceau : une URL PUT signée avec sa longueur exacte.
const url = await store.presignUploadPart(key, uploadId, partNumber, { contentLength, expiresIn: 3600 })

// Pour reprendre : les morceaux que le bucket a déjà, ou null si l’envoi n’existe plus.
const parts = await store.listUploadedParts(key, uploadId)

// Le client renvoie l’ETag de chaque morceau.
await store.completeMultipartUpload(key, uploadId, [{ partNumber: 1, etag }], { ifAbsent: true })

// Ou l’abandonner, ce qui libère les morceaux déjà stockés.
await store.abortMultipartUpload(key, uploadId)

maxSize n’est pas vérifié ici : la taille n’est connue qu’une fois les morceaux arrivés. Relisez-la avec head() après l’assemblage. ifAbsent envoie If-None-Match: * avec l’assemblage ; AWS S3 le respecte, vérifiez que votre fournisseur aussi. Le bucket a besoin d’une règle CORS qui autorise PUT et expose ETag.

transferFileObject(code, { filename, contentType?, expiresAt? }) donne la clé, le type et les métadonnées qui font d’un objet un colis que les routes du protocole reconnaissent : à passer à createMultipartUpload() pour qu’un fichier arrivé en morceaux ne se distingue pas d’un autre.

Les enregistrements JSON

putSnapshot() et getSnapshot() stockent de petits objets JSON, compressés en gzip, avec une expiration vérifiée à la lecture. La page de livraison s’en sert pour l’accusé de réception et les options d’un colis ; la CLI s’en sert pour la sonde de colis verifier --remote.

await store.putSnapshot(
  `meta/${code}.verdict`,
  { decision: 'approved', at: new Date().toISOString() },
  {
    expiresIn: 7 * 86_400,
    ifAbsent: true, // la première écriture gagne, les suivantes lèvent PRECONDITION_FAILED
  },
)

const record = await store.getSnapshot<{ decision: string }>(`meta/${code}.verdict`)
record?.data.decision // null si absent ou expiré
Option de putSnapshotEffet
app, deviceDes étiquettes libres, rendues à la lecture.
versionUn numéro de schéma ; getSnapshot(…, { maxVersion }) refuse plus récent avec SNAPSHOT_TOO_NEW.
expiresInSecondes. Passé ce délai, getSnapshot() renvoie null.
compresstrue par défaut.
ifMatch, ifAbsentÉcritures conditionnelles, comme pour upload().
prefix, signalComme partout.

getSnapshot() renvoie { data, app, device, version, createdAt, expiresAt, etag, size, bucket, key, path }, ou null pour une clé absente comme pour une clé expirée.

Les codes

store.codes crée et relit les codes, dans la forme configurée par syncCode :

store.codes.create() // "K7QP2M4X"
store.codes.normalize('k7qp-2m4x') // "K7QP2M4X"
MembreRôle
create()Un nouveau code.
normalize(input)Ce qu’on a tapé, remis en forme. Lève INVALID_SYNC_CODE si un caractère ne peut pas y figurer.
alphabet, lengthLa forme configurée.
entropyBitsCe que vaut un code face à quelqu’un qui devine : 40 par défaut.

createSyncCodes(options?), createSyncCode(), normalizeSyncCode() et syncCodeAlphabets font la même chose hors d’un bucket. Voir Configuration.

Le gestionnaire de routes

createTransferHandler({ bucket, … }) sert les quatre routes du protocole sur n’importe quoi qui parle Request et Response. Ses options (basePath, expiresIn, authorize, raw, app, maxVersion) sont décrites dans Protocole.

Le reste

  • store.client : le S3Client sous-jacent, pour tout ce que colis ne couvre pas (lister, administrer).
  • store.destroy() : libère les connexions du client créé par colis. Un client passé par config.client reste à vous.
  • ColisError et isColisError(error) : voir Erreurs.

Sur cette page