Files
zeekayandHanzo Dev 2c4319f61e storage: one object store, ours — and the gate that shut it off is gone
`getS3ClientAndConfig` threw "Invalid upload transport" unless
NEXT_PUBLIC_UPLOAD_TRANSPORT was "s3". The deployment does not set that variable
— it configures storage through NEXT_PRIVATE_UPLOAD_* (transport s3, bucket
dataroom, endpoint http://s3:9000, credentials) — so every call through that
helper threw in production while a correctly configured bucket sat beside it.
The two put paths keyed on the same unset variable and fell to `.otherwise()`,
returning { type: null, data: null }: a server-side upload reported success and
stored nothing.

There is one object store now, so nothing chooses a transport. The VERCEL_BLOB
arms are gone from get/put/copy/delete, CSV exports write through putFileServer,
and branding + expired-export deletion go through deleteFile.

Safe to remove rather than migrate: the database has no rows to orphan —
Document, DocumentVersion, Team and User are all 0, so nothing is stored under a
VERCEL_BLOB path.

The cleanup queue now carries teamId, which deleteFile needs to resolve the
storage region, and its item is a `path` rather than a `blobUrl` — the scheduler
was testing `startsWith("https://")` to decide whether to enqueue, which a
storage path never matches.

Verified with npx tsc --noEmit: 100 -> 99. The one fixed is get-file.ts, whose
ts-pattern match is no longer there to be uncallable. Nothing introduced: the
two duplicate.ts files that looked new carry identical error counts before and
after and were never touched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-09 11:23:32 -07:00

56 lines
1.7 KiB
TypeScript

import { LambdaClient } from "@aws-sdk/client-lambda";
import { S3Client } from "@aws-sdk/client-s3";
import { type StorageConfig, getStorageConfig } from "@/lib/storage/config";
/**
* Resolves the storage config.
*
* There is one object store — ours — so there is no transport to choose. This
* used to refuse unless NEXT_PUBLIC_UPLOAD_TRANSPORT was "s3", a variable the
* deployment never set: it configures S3 through NEXT_PRIVATE_UPLOAD_*, so every
* call through here threw "Invalid upload transport" in production while the
* bucket, endpoint and credentials sat correctly configured beside it.
*
* getStorageConfig() still throws when a required variable is missing — an
* upload route that cannot name its bucket must fail at the boundary rather
* than write somewhere unintended.
*/
function requireS3Config(): StorageConfig {
return getStorageConfig();
}
/** S3 client plus the config it was built from. */
export function getS3ClientAndConfig(): {
client: S3Client;
config: StorageConfig;
} {
const config = requireS3Config();
const client = new S3Client({
endpoint: config.endpoint,
region: config.region,
// Path-style addressing keeps S3-compatible endpoints working.
forcePathStyle: Boolean(config.endpoint),
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
});
return { client, config };
}
/** Lambda client for the document-conversion functions. */
export function getLambdaClient(): LambdaClient {
const config = requireS3Config();
return new LambdaClient({
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
});
}