Salta ai contenuti

@guestcraft/storage

Questi contenuti non sono ancora disponibili nella tua lingua.

GuestCraft’s object storage adapters: the ObjectStore port of @guestcraft/core/files over an S3-compatible bucket or a private Vercel Blob store (ADR 0046). It is the backend integration package of the repository rules: it imports only core, reads no environment, and server composes it from its configuration. The file store of db uses the port: it writes an object before the row that names it, and the worker’s orphan collection deletes objects that no row names.

Factory Store
s3ObjectStore({ endpoint, region, bucket, accessKeyId, secretAccessKey, forcePathStyle, fetch? }) An S3-compatible bucket: AWS S3, Cloudflare R2, MinIO, Supabase Storage’s S3 endpoint
vercelBlobObjectStore({ token?, storeId?, api? }) A private Vercel Blob store, through @vercel/blob

Both implement put, get (undefined for a missing object), delete (which succeeds for a missing object) and list, which lists the keys under a prefix (db names objects <instance>/<workspace>/<key>, and the orphan collection lists only its instance’s prefix) and pages with an opaque cursor that a caller may store: S3 continues after the last key listed (start-after of ListObjectsV2), Vercel Blob with its own cursor.

  • Requests are signed with AWS Signature Version 4 by aws4fetch, with the SHA-256 of the body in x-amz-content-sha256, so the service checks the bytes too.
  • endpoint may carry a path (Supabase’s /storage/v1/s3); forcePathStyle puts the bucket in the path rather than in the host name, as MinIO and Supabase need. Keys are percent-encoded per segment as SigV4 canonicalizes them; a key with a . or .. segment, which the URL would resolve to another object, is refused as a bug.
  • The listing’s XML is read minimally: the IsTruncated flag and each object’s Key and LastModified, with the five predefined XML entities and numeric character references decoded. An answer without them, or with a reference to no Unicode character, is refused.
  • Each request is sent once, with a 10-second limit: the file store calls object storage inside its database transaction. A failure is an InfrastructureError (ADR 0008): HTTP 408, 429 and 5xx and an unreachable service are retryable; other statuses are not; a write whose answer was lost has an unknown outcome. The message names the method and the status only: the answer’s body, which may name the key, is discarded.

The settings of each provider are in the installation guide.

Objects are written with access: "private", addRandomSuffix: false and allowOverwrite: true, so each has exactly its key as its name and is read only with the store’s credentials. The store authenticates with the read-write token, or, without one, the SDK uses the deployment’s Vercel OIDC token for the store of storeId. The SDK is loaded by a store’s first call, so an instance without Vercel Blob never loads it. Every call, with the SDK’s own retries, ends after 10 seconds. A failure that remains is an InfrastructureError, retryable for an unavailable or rate-limited service (with its Retry-After), an unknown server error, a call that timed out, and the plain BlobError that get throws for any failed answer; not retryable for any other refusal of the SDK.

Not exercised against a real store in CI. The four SDK calls sit behind the small BlobApi interface, and the unit tests replace it: they check the options sent and the conversion of the answers and errors, not Vercel’s service. Verify uploads and downloads on a deployment after enabling it.

Terminal window
pnpm --filter @guestcraft/storage test # unit tests, no Docker
pnpm --filter @guestcraft/storage test:integration # the S3 adapter against MinIO (Docker)

The unit tests check the signature of a request against an independent implementation of SigV4, itself checked against AWS’s published example. The integration tests start MinIO with @guestcraft/testing/minio and run a round trip, overwrites, missing keys, paging with names that need escaping, and a refused secret. The file store, the orphan collection and the move command are tested on PostgreSQL and MinIO in packages/server/test/integration/object-storage.integration.test.ts.