Skip to content

Compatibilitat S3

Utilitza l'AWS SDK per pujar, descarregar i gestionar fitxers a IPFS Ninja amb el mateix codi que fas servir per a Amazon S3.

Endpoint

https://s3.ipfs.ninja

Credencials

L'API S3 utilitza la teva clau API d'IPFS Ninja per a l'autenticació. La teva clau API serveix tant com a access key com a secret key.

Com obtenir les teves credencials

  1. Ves a Dashboard > API Keys
  2. Fes clic a Create API key i dona-li un nom (p. ex. "S3 access")
  3. Copia la clau completa immediatament — només es mostra un cop i no es pot recuperar més tard

La teva clau té aquest aspecte:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 prefix (12 chars)    rest of key

Correspondència amb credencials AWS

Paràmetre AWSValorExemple
accessKeyIdEls primers 12 caràcters de la teva clau APIbws_628bba35
secretAccessKeyLa clau API completa (els 36 caràcters)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionSempre us-east-1us-east-1

WARNING

La clau API completa només es mostra un cop quan la crees. Si la perds, elimina la clau i crea'n una de nova des de la pàgina d'API Keys.

Inici ràpid

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Buckets = Carpetes

Els buckets S3 es corresponen amb les teves carpetes d'IPFS Ninja. Quan puges un fitxer a un bucket, s'emmagatzema a la carpeta corresponent. Quan llistes objectes d'un bucket, veus els fitxers d'aquella carpeta.

Operació S3Equivalent a IPFS Ninja
CreateBucketCrear una carpeta nova
ListBucketsLlistar les teves carpetes
DeleteBucketEliminar una carpeta i tots els seus fitxers
PutObject a un bucketPujar un fitxer a la carpeta
ListObjectsV2 d'un bucketLlistar els fitxers de la carpeta
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

Les carpetes creades mitjançant l'API S3 són les mateixes carpetes visibles al teu Dashboard. Pots organitzar fitxers des de l'API S3, l'API REST o la interfície web — tots comparteixen el mateix sistema de carpetes.

INFO

A diferència d'Amazon S3, les carpetes d'IPFS Ninja són planes per defecte. Per crear estructures imbricades, utilitza els endpoints de carpetes de l'API REST amb parentFolderId. Des de l'API S3, utilitza prefixos de clau (p. ex. images/photo.png) per organitzar dins d'una carpeta.

Els noms de bucket són únics globalment

Els noms de bucket viuen en un espai de noms global compartit entre tots els clients, igual que la semàntica d'AWS S3. Això significa:

  • El primer usuari que crea un bucket amb un nom determinat reclama aquest nom globalment.
  • Les crides CreateBucket posteriors amb el mateix nom des de qualsevol compte retornen BucketAlreadyExists (409).
  • Si intentes tornar a crear el teu propi bucket, obtens BucketAlreadyOwnedByYou (409).
  • El nom de la teva carpeta al tauler de control és per compte i pot ser qualsevol cosa — només el nom del bucket visible per S3 passa per l'espai de noms global.

Si el nom que vols ja està agafat, tria'n un amb un àmbit diferent (myapp-photos-2026, acme-nft-metadata) — la mateixa convenció que faries servir a Amazon S3.

Operacions suportades

PutObject

Puja un fitxer a IPFS. El fitxer es fixa (pin), s'analitza per seguretat i el CID es retorna a les capçaleres ETag i x-amz-meta-cid.

Per importar un fitxer CAR en lloc d'un fitxer normal, afegeix la capçalera de metadata x-amz-meta-import: car. Consulteu Importació CAR per a més detalls.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# curl equivalent
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Descarrega un fitxer per la seva clau (nom de fitxer) o CID.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Obté les metadades d'un fitxer sense descarregar el contingut.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Desfixa (unpin) un fitxer d'IPFS i elimina'l del teu compte.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Llista els fitxers d'un bucket amb filtratge opcional per prefix i paginació.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Multipart Upload

Puja fitxers grans (fins a 5 GB) mitjançant multipart upload. L'AWS SDK ho gestiona automàticament:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB per part
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

O controla les parts manualment:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Start
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Upload parts
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Complete
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Exemple amb Python

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Exemple amb Go

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

Configurar CORS (accés des de l'SDK del navegador)

Si crides l'API S3 directament des de JavaScript al navegador (SPA, aplicació de wallet, eina del tauler de control), primer has de configurar CORS al bucket. Altrament els navegadors bloquegen el preflight i les teves pujades fallen amb No 'Access-Control-Allow-Origin' header is present.

Mateixa forma que a AWS S3 — subrecursos PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Límits i valors per defecte

  • Fins a 5 regles per bucket (l'especificació en permet 100; ho limitem a 5 per mantenir compacta la resposta del preflight del navegador).
  • Configuració total limitada a 64 KB serialitzats.
  • Si no hi ha cap configuració CORS establerta, els preflights del navegador es rebutgen — igual que el comportament per defecte d'AWS S3. Configura regles explícites per als orígens des dels quals realment serveixes.

Nota de seguretat pràctica

CORS és una capa de conveniència del costat del navegador, no un límit de seguretat. Cada crida a l'API S3 encara requereix una signatura SigV4 vàlida calculada a partir de la teva API key — una configuració CORS permissiva no permet que ningú utilitzi el teu bucket sense aquesta credencial. El que CORS sí que evita: que un origen no desitjat (p. ex. una còpia obsoleta de la teva aplicació a dev.myapp.com) enviï sol·licituds signades des d'un context de navegador.

Alternativa al tauler de control

La pàgina de Fitxers té una opció S3 CORS al menú d'accions de cada carpeta. Mateix emmagatzematge subjacent; si no vols escriure codi PutBucketCors, configura-ho allà.

Diferències respecte a Amazon S3

FuncionalitatAmazon S3IPFS Ninja S3
Model d'emmagatzematgeObjectes mutablesAdreçament per contingut (CID immutables)
Comportament en sobreescriureSubstitueix l'objecte al llocCrea un nou CID, l'antic CID continua accessible
VersionatSuportatNo suportat (utilitza CID per al versionat)
Xifratge al servidorSuportatNo suportat (el contingut és a IPFS)
Polítiques de cicle de vidaSuportadesNo suportades
Polítiques de bucket / ACLSuportadesUtilitza els modes d'accés del gateway
URL prefirmadesSuportadesUtilitza tokens de pujada signats
Mida màxima d'objecte5 TB5 GB (multipart), 100 MB (PUT únic)
RegionsMulti-regióNomés us-east-1
Valor d'ETagHash MD5IPFS CID
Capçaleres addicionalsS3 estàndardx-amz-meta-cid (IPFS CID)
Format de CIDN/ACIDv1 modern (bafy…) per a pujades noves; el Qm… heretat continua sent vàlid com a entrada
Espai de noms de bucketGlobal (tot AWS)Global (entre tots els comptes d'IPFS Ninja) — mateixa semàntica
CORSPutBucketCors suportatPutBucketCors suportat (límit de 5 regles)

Migració des d'Amazon S3

Substitueix la configuració del teu client S3:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

Les teves crides existents a PutObject, GetObject, ListObjectsV2 i DeleteObject funcionen sense canvis.

Migració des de Filebase

Substitueix l'URL de l'endpoint:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });