CLI
La commande colis : envoyer, recevoir, suivre et annuler un colis, vérifier une installation, et garder les réglages dans un fichier.
Le paquet npm @mdemb/colis fournit la commande colis :
npm i -g @mdemb/colis
colis --helpElle se construit aussi depuis le dépôt, voir Installation.
Son analyseur d’arguments est parseArgs de node:util. @colis/core et @colis/protocol sont
embarqués dans le build ; sa seule dépendance est le client S3 d’AWS.
Trois façons de travailler
Vers le service public, sans rien configurer. Sans --remote, sans COLIS_REMOTE, sans fichier
de configuration et sans bucket, la CLI parle à https://colis-tau.vercel.app/api/transfers : pas de
mot de passe, et un compte seulement si vous le voulez (colis connexion). Ce service est ouvert à tous, donc limité : un fichier de 100 Mo au plus, gardé 24 h au plus, et 20 envois par heure depuis une même adresse. Au-delà, le serveur répond TOO_LARGE ou RATE_LIMITED, et la CLI affiche son message
et ce qu’il faut faire. Les fichiers sont stockés dans le bucket du service ; colis config indique
quand il est utilisé.
colis envoyer ./maquette.pdf
colis statut K7QP2M4XVers votre page de livraison, avec --remote (ou remote dans le fichier de configuration).
La machine qui envoie n’a besoin d’aucune clé S3 : elle tient le DROP_PASSWORD du déploiement,
qui tient les clés. C’est le mode à utiliser pour livrer à un client : le déploiement tient
l’accusé de réception et envoie les webhooks.
colis --remote https://votre-livraison.vercel.app/api/transfers --token "$DROP_PASSWORD" envoyer ./maquette.pdfDirectement vers le bucket, dès qu’un bucket est configuré (--bucket, COLIS_BUCKET ou
bucket dans le fichier) et sans --remote. La CLI utilise les identifiants S3 de la machine et
écrit dans le bucket elle-même. Pratique pour tester un bucket ou échanger un fichier entre vos
propres machines, mais sans page de retrait, sans accusé et sans webhook : ce sont des fonctions du
déploiement.
Ce n’est pas une seconde implémentation. La CLI n’en a qu’une, le client du
protocole, branché soit sur fetch, soit directement sur le gestionnaire de
routes dans le même processus.
envoyer
$ colis envoyer ./maquette-v2.pdf
maquette-v2.pdf · 1.8 MB · expires in 1 day
K7QP2M4XLe code va sur stdout et tout le reste sur stderr, donc la commande se compose :
CODE=$(colis envoyer ./maquette-v2.pdf)- lit stdin, ce qui permet d’envoyer un dossier :
tar cz ./export | colis envoyer - --name export.tar.gz--name change le nom sous lequel le fichier est stocké. --expires-in règle la durée de vie
(3600, 30m, 24h, 7d ou never). Vers une page de livraison, elle n’est envoyée que si vous
la donnez, et le serveur la garde dans les limites de votre formule : au-delà de la formule
gratuite, PLAN_LIMIT si la formule Pro l’accepterait ; sans l’option, c’est
la durée par défaut du déploiement. never n’y a pas de sens et est refusé.
Vers une page de livraison (le service public compris), un fichier de 4 Mo au plus part en une requête. Au-delà, la CLI passe par les routes d’envoi direct, comme la page : les morceaux vont droit au bucket, et aucune règle CORS n’est nécessaire hors navigateur. Voir Gros fichiers.
Une nouvelle version : --remplace
Le client a demandé des corrections ? Envoyez la version corrigée sous le même code :
$ colis envoyer ./maquette-v3.pdf --remplace K7QP2M4X
maquette-v3.pdf · 1.9 MB · expires in 1 day
Version 2 envoyée sur K7QP2M4X
K7QP2M4XLe client rouvre le même lien et y trouve la nouvelle version, avec l’historique des précédentes.
Seul l’expéditeur peut le faire, et seulement après « corrections demandées » : un livrable validé
est clos. La preuve, c’est le jeton d’expéditeur que la page de livraison remet à chaque envoi ; la
CLI le garde dans ~/.config/colis/envois.json (ou sous $XDG_CONFIG_HOME), lisible par vous seul,
donc --remplace marche depuis la machine qui a fait le premier envoi. Voir
Suivi et validation.
recevoir
$ colis recevoir k7qp-2m4x
Wrote /home/vous/maquette-v2.pdf · 1.8 MBLe fichier est écrit sous son nom d’origine, ou sous -o <chemin> ; -o - l’écrit sur stdout. Le
code se tape comme on veut : casse et tirets sont ignorés. Pour un colis protégé par un mot de passe,
passez-le avec --token.
statut
L’accusé de réception d’un colis : envoyé, ouvert, validé ou à corriger.
$ colis statut K7QP2M4X
à corriger
envoyé 2026-09-22 10:00
ouvert 2026-09-22 11:00
à corriger 2026-09-22 12:00
comment Le logo en SVG, et le fond plus clair.La première ligne est l’état seul, pour colis statut K7QP2M4X | head -1 dans un script ; --json
donne l’objet complet (code, status, sentAt, openedAt, decidedAt, comment, isSender,
version, versions). Après un --remplace, l’état est celui de la version en cours ; la sortie
ajoute version 2 of 2 et une ligne par version précédente, avec la réponse du client. Depuis la
machine qui a envoyé le colis, statut joint le jeton d’expéditeur, et isSender vaut true.
statut interroge une page de livraison : l’accusé est tenu par elle, pas par le bucket. Sans rien
configurer, c’est le service public. Avec un bucket et sans --remote, la commande le dit, indique
seulement si le colis est encore là, et sort en erreur.
Voir Suivi et validation.
annuler
$ colis annuler K7QP2M4X
Burned K7QP2M4XDétruit le colis tout de suite ; sinon il expire seul. Annuler un code déjà disparu n’est pas une
erreur. Vers une page de livraison, cela envoie parcel.deleted.
connexion, compte et deconnexion
Un compte est facultatif. Connecté, vos envois vers ce serveur sont rattachés à votre compte, et la limite d’envois par heure se compte par compte plutôt que par adresse.
$ colis connexion
Ouvrez https://colis-tau.vercel.app/connexion?code=BCDF-GHJK
et confirmez le code BCDF-GHJK (valable 10 min).
En attente de la confirmation…
Connecté en tant que vous@exemple.fr.La page s’ouvre dans le navigateur quand c’est possible ; connectez-vous-y par lien e-mail si ce
n’est pas déjà fait, vérifiez que le code est bien celui du terminal, puis confirmez. La CLI attend
la confirmation et garde la session un an dans ~/.config/colis/compte.json, lisible par vous seul,
comme envois.json. Ensuite, colis envoyer l’envoie en Authorization: Bearer à ce serveur.
$ colis compte
vous@exemple.fr
formule Pro
taille jusqu’à 2 Go par fichier
durée jusqu’à 30 jours par lien
envois 200 par heure
renouvellement 27 octobre 2026 (mensuel)
serveur https://colis-tau.vercel.app/api
$ colis deconnexion
Déconnecté de vous@exemple.fr.Sur un serveur qui propose la formule Pro :
colis compte pro # ouvre le paiement Stripe, abonnement mensuel
colis compte pro --annuel # abonnement annuel
colis compte gerer # carte, factures, résiliationLa page de paiement s’ouvre dans le navigateur quand c’est possible, et son adresse est toujours
affichée. Un envoi qui dépasse les limites de la formule gratuite, mais pas celles de Pro, échoue en
PLAN_LIMIT : la CLI affiche le message du serveur et rappelle colis compte pro.
deconnexion révoque la session sur le serveur, puis l’oublie sur la machine. Une session expirée
ou révoquée fait échouer l’envoi en INVALID_SESSION plutôt que de l’envoyer anonymement :
reconnectez-vous, ou déconnectez-vous pour envoyer sans compte. Avec --token (le DROP_PASSWORD
d’un serveur privé), c’est lui qui occupe l’en-tête et la session n’est pas envoyée.
verifier
La commande à lancer en premier. Contre un bucket, elle effectue les opérations dont colis a besoin et rapporte ce qui s’est passé :
$ colis verifier
Using /home/vous/livraisons/colis.config.json
✓ Configuration: bucket "livraisons", region "auto", https://….r2.cloudflarestorage.com
✓ Credentials: resolved, key ends in 1a2b
✓ Bucket reachable: HeadBucket succeeded
✓ Write, read, delete: round-tripped a probe object
! Expiry cleanup: no enabled expiration rule
→ Add an S3 lifecycle rule that expires objects under …
! Browser uploads (CORS): no CORS configuration
→ For large files in the colis drop, add a CORS rule allowing PUT from your site and exposing ETag. …Les deux derniers contrôles sont des avertissements : la règle de cycle de vie, sans laquelle les colis expirés restent stockés et facturés, et la règle CORS dont les gros fichiers ont besoin. L’objet de test est supprimé avant la fin.
Contre une page de livraison, elle vérifie la seule chose qui compte, un vrai aller-retour :
$ colis verifier --remote https://votre-livraison.vercel.app/api/transfers --token "$DROP_PASSWORD"
✓ Server: https://votre-livraison.vercel.app/api/transfers answered
✓ Create, read, delete: round-tripped code 8WTXQC8RElle sort en erreur si un contrôle échoue, donc colis verifier --json sert de test après un
déploiement.
init
Écrit un colis.config.json de départ pour un fournisseur, puis dit ce qu’il reste à faire :
$ colis init --provider r2 --bucket livraisons
Wrote /home/vous/livraisons/colis.config.json
Put the three values in .env, and keep it out of git:
R2_ACCOUNT_ID=…
R2_ACCESS_KEY_ID=…
R2_SECRET_ACCESS_KEY=…
…--provider accepte aws, r2, minio, scaleway, wasabi ou remote. remote écrit une
configuration qui parle à une page de livraison, avec le jeton lu dans COLIS_TOKEN. La commande
refuse d’écraser un fichier existant sans --force, et écrit ailleurs avec --config <chemin>.
config
Ce que la CLI a retenu, et d’où vient chaque valeur :
$ colis config
file /home/vous/livraisons/colis.config.json (profile "prod")
profiles prod, local
mode https://votre-livraison.vercel.app/api/transfers (over HTTP)Elle n’affiche jamais un secret (l’identifiant de clé est masqué à ses quatre derniers caractères, le jeton est seulement signalé comme présent) et ne contacte rien : elle fonctionne avant tout le reste.
Le fichier de configuration
Tout ce que prennent les options, dans un fichier que la CLI trouve seule :
{
"remote": "https://votre-livraison.vercel.app/api/transfers",
"token": "${COLIS_TOKEN}",
"envFile": ".env"
}La CLI cherche --config <chemin> ou $COLIS_CONFIG, puis colis.config.json, .colisrc.json ou
.colisrc en remontant depuis le dossier courant, puis ~/.config/colis/config.json. Le premier
trouvé l’emporte. ${VAR} est lu dans l’environnement, et envFile charge un fichier KEY=value
d’abord : le fichier peut être versionné, pas les secrets.
Plusieurs réglages dans un seul fichier, choisis avec -p ou $COLIS_PROFILE :
{
"envFile": ".env",
"profiles": {
"prod": { "remote": "https://votre-livraison.vercel.app/api/transfers", "token": "${COLIS_TOKEN}" },
"local": { "remote": "http://localhost:3400/api/transfers" }
}
}colis -p local verifier
colis -p prod envoyer ./maquette.pdfChaque clé et chaque variable d’environnement sont dans Configuration.
Options
| Option | Effet |
|---|---|
-c, --config <path> | Le fichier de configuration à lire |
-p, --profile <name> | Le profil à utiliser dans ce fichier |
--env-file <path> | Lire d’abord les paires KEY=value de ce fichier |
--bucket <name> | Nom du bucket |
--prefix <prefix> | Préfixe des clés dans le bucket |
--region <name> | Région |
--endpoint <url> | Point d’accès compatible S3 : R2, MinIO, Scaleway, Wasabi… |
--expires-in <d> | Durée de vie : 3600, 30m, 24h, 7d ou never, envoyée aussi à une page de livraison |
--annuel | Avec compte pro : l’abonnement annuel plutôt que mensuel |
--remote <url> | Parler à une page de livraison plutôt qu’au bucket |
--token <token> | Jeton Bearer envoyé avec --remote : le DROP_PASSWORD, ou le mot de passe d’un colis protégé |
--name <filename> | Nom sous lequel stocker le fichier |
-o, --output <path> | Où recevoir écrit. - pour stdout |
--json | Sortie lisible par une machine |
--provider <name> | Le modèle qu’écrit init |
--force | Autoriser init à écraser un fichier existant |
-h, --help | L’aide |
-v, --version | La version |
Les anciens noms de s3nd restent des alias : put pour envoyer, get pour recevoir, rm pour
annuler, doctor pour verifier.
Chaque commande sort avec un code non nul quand elle échoue. La couleur disparaît quand la sortie n’est pas un
terminal, et quand NO_COLOR est défini.