Stockage (téléversements pré-signés)

Le serveur génère une URL PUT pré-signée ; le navigateur téléverse directement vers S3/R2 — les octets ne traversent jamais bext. Même principe pour la lecture : le serveur génère une URL GET pré-signée, la page redirige vers elle ou y crée un lien. Le choix du backend (S3, R2, local) est un simple paramètre de configuration.

Astuce
Les URLs pré-signées expirent (ici 300s) et ne sont valables que pour la clé précise. Ne les mettez jamais en cache côté client ni ne les loguez — elles accordent un accès temporaire sans authentification supplémentaire.
Backend non configuré sur ce site. Le formulaire ci-dessous affichera le chemin d'erreur ; la surface d'API et la forme de configuration sont exactes, mais aucun téléversement réel n'a lieu tant que [storage] n'est pas défini dans bext.config.toml. Ajoutez l'extrait sous Configuration, redémarrez, et la démo devient active.

Essayer

backend non configuré

bext.config.tomlTOML
# bext.config.toml — wire up an S3-compatible backend.
[storage]
provider    = "s3"          # or "r2", "local"
bucket      = "my-bucket"
region      = "us-east-1"
endpoint    = "https://s3.amazonaws.com"
access_key  = "AKIA..."     # use an env var in production
secret_key  = "..."
public_base = "https://cdn.example.com"  # optional
src/app/examples/storage/page.tsxTSX
// src/app/examples/storage/page.tsx — server: mint presigned URLs.
import { presignPut, presignGet, publicUrl } from "@bext-stack/framework/storage";

export async function action({ request }) {
  const key = "demo/" + Date.now() + ".txt";
  return Response.json({
    putUrl: presignPut(key, { ttlSecs: 300 }),
    getUrl: presignGet(key, 300),
    publicUrl: publicUrl(key),  // null when backend has no public URL
    key,
  });
}

// Client: PUT directly to S3/R2 — bytes never traverse bext.
const r = await fetch("/examples/storage", { method: "POST", body: form });
const { putUrl } = await r.json();
await fetch(putUrl, {
  method: "PUT",
  body: file,
  headers: { "content-type": file.type },
});