Compare commits
1 Commits
fix/react-
...
feat/virtu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
575526a341 |
@@ -32,6 +32,7 @@ NEXT_PUBLIC_STORAGE_URL=
|
|||||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME=
|
||||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=
|
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=
|
||||||
NEXT_PUBLIC_STORAGE_DOMAIN=
|
NEXT_PUBLIC_STORAGE_DOMAIN=
|
||||||
|
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=
|
||||||
|
|
||||||
# Auth config (optional)
|
# Auth config (optional)
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS=
|
NEXT_PUBLIC_ALLOW_CREDENTIALS=
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ pnpm dev
|
|||||||
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
|
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
|
||||||
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
|
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
|
||||||
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
|
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
|
||||||
|
| `NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS` | Use virtual-hosted style URLs (bucket.domain.com) | For file uploads (optional) | `true` |
|
||||||
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
|
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
|
||||||
| `NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME` | S3 bucket name for attachments | For file uploads | `attachments` |
|
| `NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME` | S3 bucket name for attachments | For file uploads | `attachments` |
|
||||||
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
|
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(),
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME: z.string().optional(),
|
||||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME: z.string().optional(),
|
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME: z.string().optional(),
|
||||||
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
|
NEXT_PUBLIC_STORAGE_DOMAIN: z.string().optional(),
|
||||||
|
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: z
|
||||||
|
.string()
|
||||||
|
.transform((s) => (s === "" ? undefined : s))
|
||||||
|
.refine(
|
||||||
|
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
NEXT_PUBLIC_APP_VERSION: z.string().optional(),
|
NEXT_PUBLIC_APP_VERSION: z.string().optional(),
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
|
NEXT_PUBLIC_ALLOW_CREDENTIALS: z
|
||||||
.string()
|
.string()
|
||||||
@@ -134,6 +141,8 @@ export const env = createEnv({
|
|||||||
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME:
|
NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME:
|
||||||
process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME,
|
process.env.NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME,
|
||||||
NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN,
|
NEXT_PUBLIC_STORAGE_DOMAIN: process.env.NEXT_PUBLIC_STORAGE_DOMAIN,
|
||||||
|
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS:
|
||||||
|
process.env.NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS,
|
||||||
NEXT_PUBLIC_APP_VERSION: process.env.NEXT_PUBLIC_APP_VERSION,
|
NEXT_PUBLIC_APP_VERSION: process.env.NEXT_PUBLIC_APP_VERSION,
|
||||||
NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS,
|
NEXT_PUBLIC_ALLOW_CREDENTIALS: process.env.NEXT_PUBLIC_ALLOW_CREDENTIALS,
|
||||||
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
|
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ describe("getAvatarUrl", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("virtual-hosted URLs (Tigris/AWS S3)", () => {
|
describe("virtual-hosted URLs (Tigris/AWS S3)", () => {
|
||||||
it("constructs virtual-hosted URL when STORAGE_DOMAIN is set", () => {
|
it("constructs virtual-hosted URL when USE_VIRTUAL_HOSTED_URLS is true and STORAGE_DOMAIN is set", () => {
|
||||||
mockEnv.mockImplementation((key: string) => {
|
mockEnv.mockImplementation((key: string) => {
|
||||||
const vars: Record<string, string> = {
|
const vars: Record<string, string> = {
|
||||||
|
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: "true",
|
||||||
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
|
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
|
||||||
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
|
||||||
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
|
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
|
||||||
@@ -65,5 +66,36 @@ describe("getAvatarUrl", () => {
|
|||||||
"https://kan-avatars.fly.storage.tigris.dev/user123/avatar.jpg",
|
"https://kan-avatars.fly.storage.tigris.dev/user123/avatar.jpg",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses path-style URL when USE_VIRTUAL_HOSTED_URLS is false even if STORAGE_DOMAIN is set", () => {
|
||||||
|
mockEnv.mockImplementation((key: string) => {
|
||||||
|
const vars: Record<string, string> = {
|
||||||
|
NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS: "false",
|
||||||
|
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
|
||||||
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
|
||||||
|
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
|
||||||
|
};
|
||||||
|
return vars[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
|
||||||
|
"https://fly.storage.tigris.dev/kan-avatars/user123/avatar.jpg",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses path-style URL when USE_VIRTUAL_HOSTED_URLS is not set even if STORAGE_DOMAIN is set", () => {
|
||||||
|
mockEnv.mockImplementation((key: string) => {
|
||||||
|
const vars: Record<string, string> = {
|
||||||
|
NEXT_PUBLIC_STORAGE_DOMAIN: "fly.storage.tigris.dev",
|
||||||
|
NEXT_PUBLIC_AVATAR_BUCKET_NAME: "kan-avatars",
|
||||||
|
NEXT_PUBLIC_STORAGE_URL: "https://fly.storage.tigris.dev",
|
||||||
|
};
|
||||||
|
return vars[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getAvatarUrl("user123/avatar.jpg")).toBe(
|
||||||
|
"https://fly.storage.tigris.dev/kan-avatars/user123/avatar.jpg",
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -53,9 +53,10 @@ export const getAvatarUrl = (imageOrKey: string | null) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bucket = env("NEXT_PUBLIC_AVATAR_BUCKET_NAME");
|
const bucket = env("NEXT_PUBLIC_AVATAR_BUCKET_NAME");
|
||||||
|
const useVirtualHostedUrls = env("NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS");
|
||||||
const storageDomain = env("NEXT_PUBLIC_STORAGE_DOMAIN");
|
const storageDomain = env("NEXT_PUBLIC_STORAGE_DOMAIN");
|
||||||
|
|
||||||
if (storageDomain) {
|
if (useVirtualHostedUrls === "true" && storageDomain) {
|
||||||
return `https://${bucket}.${storageDomain}/${imageOrKey}`;
|
return `https://${bucket}.${storageDomain}/${imageOrKey}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ services:
|
|||||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||||
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
||||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||||
|
- NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=${NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS}
|
||||||
|
|
||||||
# Auth config (optional)
|
# Auth config (optional)
|
||||||
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ services:
|
|||||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||||
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
- NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME=${NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME}
|
||||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||||
|
- NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS=${NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS}
|
||||||
|
|
||||||
# White label
|
# White label
|
||||||
- NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY=${NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY}
|
- NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY=${NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
"STRIPE_TEAM_PLAN_YEARLY_PRICE_ID",
|
"STRIPE_TEAM_PLAN_YEARLY_PRICE_ID",
|
||||||
"NEXT_PUBLIC_STORAGE_DOMAIN",
|
"NEXT_PUBLIC_STORAGE_DOMAIN",
|
||||||
"NEXT_PUBLIC_STORAGE_URL",
|
"NEXT_PUBLIC_STORAGE_URL",
|
||||||
|
"NEXT_PUBLIC_USE_VIRTUAL_HOSTED_URLS",
|
||||||
"NEXT_PUBLIC_AVATAR_BUCKET_NAME",
|
"NEXT_PUBLIC_AVATAR_BUCKET_NAME",
|
||||||
"NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME",
|
"NEXT_PUBLIC_ATTACHMENTS_BUCKET_NAME",
|
||||||
"NEXT_PUBLIC_ALLOW_CREDENTIALS",
|
"NEXT_PUBLIC_ALLOW_CREDENTIALS",
|
||||||
|
|||||||
Reference in New Issue
Block a user