Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update cdn url #1123

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const nextConfig = {
images: {
remotePatterns: [
{
hostname: "utfs.io",
pathname: "/a/s40vlb3kca/*",
hostname: "s40vlb3kca.ufs.sh",
pathname: "/f/*",
},
],
},
Expand Down
2 changes: 1 addition & 1 deletion docs/src/app/(api)/api/og/blog/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const GET = async (req: Request) => {
tw="bg-zinc-900 h-full w-full flex flex-col p-14"
style={{
backgroundImage:
"url(https://utfs.io/f/656e69ef-2800-45fd-87ac-b9f88346348c-hi270o.png)",
"url(https://s40vlb3kca.ufs.sh/f/656e69ef-2800-45fd-87ac-b9f88346348c-hi270o.png)",
backgroundPosition: "cover",
}}
>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/app/(api)/api/og/docs/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const GET = async (req: Request) => {
tw="bg-zinc-900 h-full w-full flex flex-col p-14"
style={{
backgroundImage:
"url(https://utfs.io/f/656e69ef-2800-45fd-87ac-b9f88346348c-hi270o.png)",
"url(https://s40vlb3kca.ufs.sh/f/656e69ef-2800-45fd-87ac-b9f88346348c-hi270o.png)",
backgroundPosition: "cover",
}}
>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/app/(docs)/concepts/regions-acl/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ you can select the region you want to upload your files to. Once changed, all
## Access Controls

By default every file uploaded to UploadThing is accessible simply by it's URL
(`utfs.io/f/FILE_KEY`). Although this hard-to-guess URL is fine for many
(`APP_ID.ufs.sh/f/FILE_KEY`). Although this hard-to-guess URL is fine for many
applications, some applications require a more secure way to store their files.

You can configure your app's access control list (ACL) to restrict access to
Expand Down
41 changes: 18 additions & 23 deletions docs/src/app/(docs)/working-with-files/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,28 @@ export const metadata = docsMetadata({
After your files have been uploaded, you will most likely want to do something
with them. This page shows how to work with your uploaded files.

## Accessing Files
## Accessing Public Files

<Warning>
Do not use the raw file URL from the storage provider, e.g. `https://bucket.s3.region.amazonaws.com/<FILE_KEY>`. We reserve the right to move objects between different storage providers and/or buckets, so this URL is not guaranteed to remain valid.
</Warning>
UploadThing serves all files from a CDN at the following URL pattern:

There are multiple ways to access your files. The most generic way is to
construct the URL from the `fileKey` you get back after the file has been
uploaded:
`https://<APP_ID>.ufs.sh/f/<FILE_KEY>`

`https://utfs.io/f/<FILE_KEY>`
If you set a `customId` when uploading the file, you can also use
`https://<APP_ID>.ufs.sh/f/<CUSTOM_ID>` to access it.

This URL will always work for public files and is the default URL returned by
the API and from any SDK method. However, sometimes you may want a URL that's
scoped to your application, for example when doing image optimizations and want
to filter what URLs are allowed to be optimized on your server. For this, the
following URL can be used:
<Warning>
Do not use the raw file URL from the storage provider, e.g. `https://bucket.s3.region.amazonaws.com/<FILE_KEY>`. We reserve the right to move objects between different storage providers and/or buckets, so this URL is not guaranteed to remain valid.
</Warning>

`https://utfs.io/a/<APP_ID>/<FILE_KEY>`
<Note>
Previously, all files were served from `https://utfs.io/f/<FILE_KEY>`.
This is still supported, but not recommended and may be deprecated in the future.
</Note>

By using this URL pattern, you have more granular control over what URLs are
allowed to be optimized. Below is an example of how to setup image optimization
allow filtering in Next.js:
Given that all files are served from a subdomain of your app, you have granular
control over what URLs are allowed to be processed. Below is an example of how
to setup image optimization allow filtering in Next.js that only allows
optimizing images from your app:

```js
/** @type {import('next').NextConfig} */
Expand All @@ -43,18 +42,14 @@ export default {
remotePatterns: [
{
protocol: "https",
hostname: "utfs.io",
pathname: "/a/<APP_ID>/*",
hostname: "<APP_ID>.ufs.sh",
pathname: "/f/*",
},
],
},
};
```

<Note>
If you set a `customId` when uploading the file, you can also use `https://utfs.io/a/<APP_ID>/<CUSTOM_ID>`.
</Note>

## Accessing Private Files

If your files are protected with
Expand Down
3 changes: 2 additions & 1 deletion examples/minimal-expo/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Go to https://uploadthing.com/dashboard to get your token
UPLOADTHING_TOKEN='...'
UPLOADTHING_TOKEN='...'
EXPO_PUBLIC_UPLOADTHING_APP_ID='...'
2 changes: 1 addition & 1 deletion examples/minimal-expo/app/f/[key].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { isImage } from "~/lib/utils";
export default function FileScreen() {
const searchParams = useGlobalSearchParams<{ key: string; name?: string }>();
const { key, name = "Untitled" } = searchParams;
const fileUrl = `https://utfs.io/f/${key}`;
const fileUrl = `https://${process.env.EXPO_PUBLIC_UPLOADTHING_APP_ID}.ufs.sh/f/${key}`;

return (
<>
Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/upload-button.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const worker = setupWorker(
http.all<{ key: string }>(
"https://fra1.ingest.uploadthing.com/:key",
({ params }) => {
return HttpResponse.json({ url: "https://utfs.io/f/" + params.key });
return HttpResponse.json({ url: "https://app-1.ufs.sh/f/" + params.key });
},
),
);
Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/upload-dropzone.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const worker = setupWorker(
http.all<{ key: string }>(
"https://fra1.ingest.uploadthing.com/:key",
({ params }) => {
return HttpResponse.json({ url: "https://utfs.io/f/" + params.key });
return HttpResponse.json({ url: "https://app-1.ufs.sh/f/" + params.key });
},
),
);
Expand Down
5 changes: 5 additions & 0 deletions packages/uploadthing/src/_internal/shared-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export class UploadedFileData extends FileUploadDataWithCustomId.extend<Uploaded
)({
key: S.String,
url: S.String,
/**
* @deprecated
* This field is now an alias for `url`.
* This field will be removed in uploadthing v9.
*/
appUrl: S.String,
fileHash: S.String,
}) {}
Expand Down
5 changes: 5 additions & 0 deletions packages/uploadthing/src/_internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ export type UTEvents = {
*/
export type UploadPutResult<TServerOutput = unknown> = {
url: string;
/**
* @deprecated
* This field is now an alias for `url`.
* This field will be removed in uploadthing v9.
*/
Comment on lines +199 to +203
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Migration guidance needed for CDN URL changes

The review comment is correct. After checking the documentation:

  • No migration guide exists for the CDN URL changes and appUrl deprecation
  • The V7 migration guide doesn't cover this change
  • No examples are provided for updating existing code using appUrl
🔗 Analysis chain

LGTM! Consider adding migration guidance.

The deprecation notice is consistent with the one in shared-schemas.ts. However, since this is part of a broader CDN URL update, it would be helpful to:

  1. Add a migration guide in the documentation
  2. Provide examples of how to update existing code

Let's check if there's already a migration guide in the docs:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for migration documentation
rg -i "migration|upgrade|deprecat" "docs/"

Length of output: 2205


Script:

#!/bin/bash
# Check v7 migration guide content and search for CDN URL documentation
echo "=== V7 Migration Guide Content ==="
cat "docs/src/app/(docs)/v7/page.mdx"
echo -e "\n=== CDN URL Documentation ==="
rg -i "cdn.*url|url.*cdn|appUrl" "docs/"

Length of output: 76945

appUrl: string;
fileHash: string;
serverData: TServerOutput;
Expand Down
19 changes: 9 additions & 10 deletions packages/uploadthing/test/__test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@ export const API_URL =
typeof process !== "undefined" && process.env.UPLOADTHING_API_URL
? process.env.UPLOADTHING_API_URL
: "https://api.uploadthing.com";
export const UTFS_IO_URL =
export const UFS_HOST =
typeof process !== "undefined" && process.env.UPLOADTHING_API_URL
? "https://staging.utfs.io"
: "https://utfs.io";
? "utf-staging.com"
: "ufs.sh";
export const INGEST_URL =
typeof process !== "undefined" && process.env.UPLOADTHING_API_URL
? "https://fra1.ingest.ut-staging.com"
: "https://fra1.ingest.uploadthing.com";

export const fileUrlPattern = new RegExp(`^${UTFS_IO_URL}/f/.+$`);
export const appUrlPattern = (appId = testToken.decoded.appId) =>
new RegExp(`^${UTFS_IO_URL}/a/${appId}/.+$`);
export const fileUrlPattern = (appId = testToken.decoded.appId) =>
new RegExp(`^https://${appId}.${UFS_HOST}/f/.+$`);

export const createApiUrl = (slug: string, action?: typeof ActionType.Type) => {
const url = new URL("http://localhost:3000");
Expand Down Expand Up @@ -86,7 +85,7 @@ export const handlers = [
await callRequestSpy(request);
return HttpResponse.text("Lorem ipsum doler sit amet");
}),
http.get(`${UTFS_IO_URL}/f/:key`, async ({ request }) => {
http.get(`https://(.+).${UFS_HOST}/f/:key`, async ({ request }) => {
await callRequestSpy(request);
return HttpResponse.text("Lorem ipsum doler sit amet");
}),
Expand All @@ -99,8 +98,8 @@ export const handlers = [
await callRequestSpy(request);
const appId = new URLSearchParams(request.url).get("x-ut-identifier");
return HttpResponse.json<UploadPutResult>({
url: `${UTFS_IO_URL}/f/${params.key}`,
appUrl: `${UTFS_IO_URL}/a/${appId}/${params.key}`,
url: `https://${appId}.${UFS_HOST}/f/${params.key}`,
appUrl: `https://${appId}.${UFS_HOST}/f/${params.key}`,
serverData: null,
fileHash: Array.from(new Uint8Array(await request.arrayBuffer()))
.map((b) => b.toString(16).padStart(2, "0"))
Expand All @@ -114,7 +113,7 @@ export const handlers = [
http.post(`${API_URL}/v6/requestFileAccess`, async ({ request }) => {
await callRequestSpy(request);
return HttpResponse.json({
url: `${UTFS_IO_URL}/f/someFileKey?x-some-amz=query-param`,
url: `https://{APP_ID}.${UFS_HOST}/f/someFileKey?x-some-amz=query-param`,
});
}),
http.post(`${API_URL}/v6/updateACL`, async ({ request }) => {
Expand Down
15 changes: 7 additions & 8 deletions packages/uploadthing/test/client.browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import type {
GenerateUploaderOptions,
} from "../src/types";
import {
appUrlPattern,
doNotExecute,
fileUrlPattern,
handlers,
Expand Down Expand Up @@ -141,8 +140,8 @@ describe("uploadFiles", () => {
serverData: null,
lastModified: expect.any(Number),
key: expect.stringMatching(/.+/),
url: expect.stringMatching(fileUrlPattern),
appUrl: expect.stringMatching(appUrlPattern()),
url: expect.stringMatching(fileUrlPattern()),
appUrl: expect.stringMatching(fileUrlPattern()),
fileHash: expect.any(String),
},
]);
Expand Down Expand Up @@ -185,8 +184,8 @@ describe("uploadFiles", () => {
serverData: null,
lastModified: expect.any(Number),
key: expect.stringMatching(/.+/),
url: expect.stringMatching(fileUrlPattern),
appUrl: expect.stringMatching(appUrlPattern()),
url: expect.stringMatching(fileUrlPattern()),
appUrl: expect.stringMatching(fileUrlPattern()),
fileHash: expect.any(String),
},
]);
Expand Down Expand Up @@ -220,8 +219,8 @@ describe("uploadFiles", () => {
serverData: null,
lastModified: expect.any(Number),
key: expect.stringMatching(/.+/),
url: expect.stringMatching(fileUrlPattern),
appUrl: expect.stringMatching(appUrlPattern()),
url: expect.stringMatching(fileUrlPattern()),
appUrl: expect.stringMatching(fileUrlPattern()),
fileHash: expect.any(String),
},
]);
Expand Down Expand Up @@ -268,7 +267,7 @@ describe("uploadFiles", () => {
// customId: null,
// serverData: null,
// key: "abc-123.txt",
// url: "https://utfs.io/f/abc-123.txt",
// url: "https://app-1.ufs.sh/f/abc-123.txt",
// },
// ]);
// expect(onErrorMock).not.toHaveBeenCalled();
Expand Down
17 changes: 9 additions & 8 deletions packages/uploadthing/test/request-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
middlewareMock,
requestSpy,
testToken,
UFS_HOST,
uploadCompleteMock,
} from "./__test-helpers";

Expand Down Expand Up @@ -409,8 +410,8 @@ describe(".onUploadComplete()", () => {
status: "uploaded",
metadata: {},
file: new UploadedFileData({
url: "https://utfs.io/f/some-random-key.png",
appUrl: `https://utfs.io/a/${testToken.decoded.appId}/some-random-key.png`,
url: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
appUrl: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
name: "foo.png",
key: "some-random-key.png",
size: 48,
Expand Down Expand Up @@ -446,8 +447,8 @@ describe(".onUploadComplete()", () => {
name: "foo.png",
size: 48,
type: "image/png",
url: "https://utfs.io/f/some-random-key.png",
appUrl: `https://utfs.io/a/${testToken.decoded.appId}/some-random-key.png`,
url: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
appUrl: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
fileHash: "some-md5-hash",
},
metadata: {},
Expand All @@ -459,8 +460,8 @@ describe(".onUploadComplete()", () => {
status: "uploaded",
metadata: {},
file: new UploadedFileData({
url: "https://utfs.io/f/some-random-key.png",
appUrl: `https://utfs.io/a/${testToken.decoded.appId}/some-random-key.png`,
url: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
appUrl: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
name: "foo.png",
key: "some-random-key.png",
size: 48,
Expand Down Expand Up @@ -492,8 +493,8 @@ describe(".onUploadComplete()", () => {
status: "uploaded",
metadata: {},
file: new UploadedFileData({
url: "https://utfs.io/f/some-random-key.png",
appUrl: `https://utfs.io/a/${testToken.decoded.appId}/some-random-key.png`,
url: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
appUrl: `https://${testToken.decoded.appId}.${UFS_HOST}/f/some-random-key.png`,
name: "foo.png",
key: "some-random-key.png",
size: 48,
Expand Down
Loading
Loading