* feat: add card attachment schema * feat: setup s3 util funcs * feat: add attachments router and repo funcs * feat: add upload button * feat: add thumbnails and attachment viewer * feat: add download and delete button * feat: add file viewer and downloads * feat: update compose and readme * chore: build lang * feat: display attachments on public boards * chore: update compiled translations
113 lines
2.9 KiB
JavaScript
113 lines
2.9 KiB
JavaScript
import { fileURLToPath } from "url";
|
|
import createJiti from "jiti";
|
|
import { env } from "next-runtime-env";
|
|
import { configureRuntimeEnv } from "next-runtime-env/build/configure.js";
|
|
|
|
// Import env files to validate at build time. Use jiti so we can load .ts files in here.
|
|
createJiti(fileURLToPath(import.meta.url))("./src/env");
|
|
|
|
configureRuntimeEnv();
|
|
|
|
/** @type {import("next").NextConfig} */
|
|
const config = {
|
|
output:
|
|
env("NEXT_PUBLIC_USE_STANDALONE_OUTPUT") === "true"
|
|
? "standalone"
|
|
: undefined,
|
|
reactStrictMode: true,
|
|
|
|
/** Enables hot reloading for local packages without a build step */
|
|
transpilePackages: [
|
|
"@kan/api",
|
|
"@kan/db",
|
|
"@kan/shared",
|
|
"@kan/auth",
|
|
"@kan/stripe",
|
|
],
|
|
|
|
/** We already do linting and typechecking as separate tasks in CI */
|
|
eslint: { ignoreDuringBuilds: true },
|
|
typescript: { ignoreBuildErrors: true },
|
|
|
|
images: {
|
|
remotePatterns: (() => {
|
|
/** @type {Array<{protocol: "http" | "https", hostname: string}>} */
|
|
const patterns = [
|
|
{
|
|
protocol: "https",
|
|
hostname:
|
|
env("S3_FORCE_PATH_STYLE") === "true"
|
|
? `${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`
|
|
: `*.${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`,
|
|
},
|
|
{
|
|
protocol: "http",
|
|
hostname: "localhost",
|
|
},
|
|
{
|
|
protocol: "https",
|
|
hostname: "*.googleusercontent.com",
|
|
},
|
|
];
|
|
|
|
// Extract root domain from S3_ENDPOINT and add wildcard pattern
|
|
const s3Endpoint = env("S3_ENDPOINT");
|
|
if (s3Endpoint) {
|
|
try {
|
|
const url = new URL(s3Endpoint);
|
|
const hostname = url.hostname;
|
|
const protocol = url.protocol.replace(":", "");
|
|
|
|
// Extract root domain (last 2 parts: e.g. cloudflarestorage.com)
|
|
const parts = hostname.split(".");
|
|
if (parts.length >= 2) {
|
|
const rootDomain = parts.slice(-2).join(".");
|
|
patterns.push({
|
|
protocol: protocol === "http" ? "http" : "https",
|
|
hostname: `*.${rootDomain}`,
|
|
});
|
|
}
|
|
} catch {
|
|
// If S3_ENDPOINT is not a valid URL, ignore it
|
|
}
|
|
}
|
|
|
|
return patterns;
|
|
})(),
|
|
},
|
|
webpack(config) {
|
|
config.module.rules.push({
|
|
test: /\.svg$/,
|
|
use: ["@svgr/webpack"],
|
|
});
|
|
return config;
|
|
},
|
|
experimental: {
|
|
// instrumentationHook: true,
|
|
swcPlugins: [["@lingui/swc-plugin", {}]],
|
|
},
|
|
|
|
async rewrites() {
|
|
return [
|
|
{
|
|
source: "/settings",
|
|
destination: "/settings/account",
|
|
},
|
|
];
|
|
},
|
|
};
|
|
|
|
// Only allow external images when OIDC is configured (for OIDC provider avatars)
|
|
if (
|
|
env("OIDC_CLIENT_ID") &&
|
|
env("OIDC_CLIENT_SECRET") &&
|
|
env("OIDC_DISCOVERY_URL")
|
|
) {
|
|
config.images?.remotePatterns?.push({
|
|
protocol: "https",
|
|
hostname: "**",
|
|
});
|
|
}
|
|
|
|
export default config;
|