@s3nd/cli
Un fichier entre deux machines, avec un code.
Déplacez un fichier avec put et get, vérifiez qu’un bucket est réellement prêt à recevoir des transferts avec doctor, et gardez les réglages dans un fichier que vous pouvez versionner. Directement vers S3 sans rien déployer, ou via votre propre serveur avec un jeton.
$ s3nd put ./report.pdf
report.pdf · 284 kB · expires in 1 day
K7QP2M4X
$ CODE=$(s3nd put ./report.pdf) # the code is stdout, the rest is stderr
$ tar cz ./project | s3nd put - --name project.tar.gz
# on the other machine
$ s3nd get K7QP2M4X
Wrote /home/you/report.pdf · 284 kB
$ s3nd get K7QP2M4X -o - | less # or to stdout
$ s3nd rm K7QP2M4X
Burned K7QP2M4Xinit et doctor
La commande à lancer en premier.
Une mauvaise configuration S3 échoue tard et vaguement. doctor effectue les opérations dont s3nd a réellement besoin et rapporte ce qui s’est passé, plutôt que de lire votre policy et de raisonner dessus. L’objet sonde est supprimé avant de rendre la main.
$ s3nd init --provider r2 --bucket transfers
Wrote /home/you/transfers/s3nd.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=…
The R2 API token needs Object Read & Write on this bucket, and nothing else.
Give the bucket a lifecycle rule that deletes objects under "transfers/" after a day or two.
Run `s3nd doctor` — it performs the operations s3nd needs and reports what happened.$ s3nd doctor
Using /home/you/transfers/s3nd.config.json
✓ Configuration: bucket "transfers", region "auto"
✓ 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 this bucket after a day or
two. Without it, expired transfers stay stored and billed.
1 check(s) failed.Cette dernière vérification est celle que personne ne découvre avant l’arrivée d’une facture. expiresIn empêche un transfert d’être remis ; seule une règle de cycle de vie supprime l’objet. Pointé sur un serveur, doctor vérifie la seule chose qui compte là-bas, un vrai aller-retour, et sort avec un code non nul en cas d’échec, donc il sert de smoke test de déploiement.
Configuration
Des réglages versionnables, des clés qui ne le sont pas.
${VAR} est lu depuis l’environnement, et envFile nomme un fichier à charger d’abord sans écraser ce que le shell a déjà défini. Les profils tiennent plusieurs configurations dans un seul fichier. Un flag bat une variable, qui bat le fichier.
{
"envFile": ".env",
"profiles": {
"r2": {
"bucket": "transfers",
"region": "auto",
"endpoint": "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com",
"expiresIn": "24h",
"credentials": { "accessKeyId": "${R2_ACCESS_KEY_ID}", "secretAccessKey": "${R2_SECRET_ACCESS_KEY}" }
},
"local": { "bucket": "transfers", "endpoint": "http://localhost:9000" },
"prod": { "remote": "https://drop.example.com/api/transfers", "token": "${S3ND_TOKEN}" }
}
}$ s3nd -p local doctor # against a MinIO container, offline
$ s3nd -p r2 put ./report.pdf
$ s3nd -p prod put ./report.pdf # through your server, with a token
$ s3nd config # which value won, and where it came from
file /home/you/transfers/s3nd.config.json (profile "r2")
mode straight to S3
bucket transfers $S3ND_BUCKET
endpoint https://8c4….r2.cloudflarestorage.com s3nd.config.json (r2)
credentials …1a2b s3nd.config.json (r2)
expires in 1 day s3nd.config.json (r2)Le fichier est cherché depuis le répertoire courant vers le haut, puis dans ~/.config/s3nd/config.json. s3nd config masque l’identifiant de clé et n’affiche jamais le secret ni le jeton. L’environnement seul fonctionne aussi, ce qui est la forme que veut la CI.
Contre votre propre serveur
Une implémentation, deux câblages.
Chaque commande accepte --remote, qui la pointe sur un déploiement du protocole de transfert au lieu de S3. La CLI a exactement une implémentation, le client du protocole, branchée soit sur fetch, soit directement sur le handler dans le même processus. Les deux modes ne peuvent pas diverger.
$ s3nd --remote https://drop.example.com/api/transfers --token "$TOKEN" put ./report.pdf
K7QP2M4X
$ s3nd doctor --remote https://drop.example.com/api/transfers --token "$TOKEN"
✓ Server: https://drop.example.com/api/transfers answered
✓ Create, read, delete: round-tripped code 8WTXQC8RConséquence pratique : la machine d’où vous lancez ça a besoin d’un jeton pour votre propre déploiement plutôt que d’identifiants S3. C’est la forme qui convient à une équipe, où donner les clés du bucket à chaque laptop ne convient pas.
s3nd init --provider remote écrit le point de départ correspondant, et doctor --remote prouve que le serveur répond avant que quiconque n’en dépende.
Référence
Six commandes, une douzaine d’options.
Commandes
- put <file>
- Stocke un fichier et affiche le code à transmettre. "-" lit stdin
- get <code>
- Récupère ce qu’un code désigne, vers le nom de fichier stocké, -o, ou stdout
- rm <code>
- Brûle un code
- doctor
- Vérifie que cette configuration peut réellement stocker des transferts. Code de sortie non nul quand une vérification échoue
- init
- Écrit un s3nd.config.json de départ pour aws, r2, minio, scaleway, wasabi ou remote
- config
- Affiche la configuration résolue, et d’où vient chaque valeur
Options
- -c, --config
- Fichier de configuration à lire
- -p, --profile
- Profil à utiliser dedans
- --env-file
- Lit d’abord des paires KEY=value depuis ce fichier
- --bucket, --prefix, --region, --endpoint
- Réglages du bucket, prioritaires sur le fichier et l’environnement
- --expires-in
- 3600, 30m, 24h, 7d, ou never
- --remote, --token
- Parle à un serveur s3nd plutôt qu’à S3 directement
- --name
- Nom de fichier sous lequel stocker le transfert
- --json
- Sortie lisible par une machine, pour les scripts et pour doctor en CI
Sinon, la configuration vient des mêmes variables d’environnement que la bibliothèque : S3ND_BUCKET, S3ND_ENDPOINT, S3ND_REMOTE, S3ND_TOKEN et les identifiants AWS habituels. Node 20 ou plus ; l’analyse des arguments est le parseArgs de node:util, donc il n’y a rien d’autre à installer.
Déposez un fichier. Donnez le code.
Pointez-le sur le bucket que vous payez déjà. Rien à déployer, aucune inscription, personne au milieu.