mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
Add support for configurable domain sub-paths (#74)
This commit is contained in:
parent
558d049d38
commit
83270ffdc9
7 changed files with 101 additions and 19 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `DOMAIN_SUB_PATH` environment variable to allow overriding the default domain subpath. ([#74](https://github.com/sourcebot-dev/sourcebot/pull/74))
|
||||||
|
|
||||||
## [2.4.3] - 2024-11-18
|
## [2.4.3] - 2024-11-18
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
# @see: https://phase.dev/blog/nextjs-public-runtime-variables/
|
# @see: https://phase.dev/blog/nextjs-public-runtime-variables/
|
||||||
ARG NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED=BAKED_NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED
|
ARG NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED=BAKED_NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED
|
||||||
ARG NEXT_PUBLIC_SOURCEBOT_VERSION=BAKED_NEXT_PUBLIC_SOURCEBOT_VERSION
|
ARG NEXT_PUBLIC_SOURCEBOT_VERSION=BAKED_NEXT_PUBLIC_SOURCEBOT_VERSION
|
||||||
|
# @note: leading "/" is required for the basePath property. @see: https://nextjs.org/docs/app/api-reference/next-config-js/basePath
|
||||||
|
ARG NEXT_PUBLIC_DOMAIN_SUB_PATH=/BAKED_NEXT_PUBLIC_DOMAIN_SUB_PATH
|
||||||
RUN yarn workspace @sourcebot/web build
|
RUN yarn workspace @sourcebot/web build
|
||||||
|
|
||||||
# ------ Build Backend ------
|
# ------ Build Backend ------
|
||||||
|
|
@ -54,6 +56,11 @@ RUN echo "Sourcebot Version: $SOURCEBOT_VERSION"
|
||||||
# Valid values are: debug, info, warn, error
|
# Valid values are: debug, info, warn, error
|
||||||
ENV SOURCEBOT_LOG_LEVEL=info
|
ENV SOURCEBOT_LOG_LEVEL=info
|
||||||
|
|
||||||
|
# Configures the sub-path of the domain to serve Sourcebot from.
|
||||||
|
# For example, if DOMAIN_SUB_PATH is set to "/sb", Sourcebot
|
||||||
|
# will serve from http(s)://example.com/sb
|
||||||
|
ENV DOMAIN_SUB_PATH=/
|
||||||
|
|
||||||
# @note: This is also set in .env
|
# @note: This is also set in .env
|
||||||
ENV POSTHOG_KEY=phc_VFn4CkEGHRdlVyOOw8mfkoj1DKVoG6y1007EClvzAnS
|
ENV POSTHOG_KEY=phc_VFn4CkEGHRdlVyOOw8mfkoj1DKVoG6y1007EClvzAnS
|
||||||
ENV NEXT_PUBLIC_POSTHOG_KEY=$POSTHOG_KEY
|
ENV NEXT_PUBLIC_POSTHOG_KEY=$POSTHOG_KEY
|
||||||
|
|
|
||||||
|
|
@ -70,23 +70,69 @@ fi
|
||||||
|
|
||||||
echo -e "\e[34m[Info] Using config file at: '$CONFIG_PATH'.\e[0m"
|
echo -e "\e[34m[Info] Using config file at: '$CONFIG_PATH'.\e[0m"
|
||||||
|
|
||||||
# Update nextjs public env variables w/o requiring a rebuild.
|
# Update NextJs public env variables w/o requiring a rebuild.
|
||||||
# @see: https://phase.dev/blog/nextjs-public-runtime-variables/
|
# @see: https://phase.dev/blog/nextjs-public-runtime-variables/
|
||||||
|
{
|
||||||
# Infer NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED if it is not set
|
# Infer NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED if it is not set
|
||||||
if [ -z "$NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED" ] && [ ! -z "$SOURCEBOT_TELEMETRY_DISABLED" ]; then
|
if [ -z "$NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED" ] && [ ! -z "$SOURCEBOT_TELEMETRY_DISABLED" ]; then
|
||||||
export NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED="$SOURCEBOT_TELEMETRY_DISABLED"
|
export NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED="$SOURCEBOT_TELEMETRY_DISABLED"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Infer NEXT_PUBLIC_SOURCEBOT_VERSION if it is not set
|
# Infer NEXT_PUBLIC_SOURCEBOT_VERSION if it is not set
|
||||||
if [ -z "$NEXT_PUBLIC_SOURCEBOT_VERSION" ] && [ ! -z "$SOURCEBOT_VERSION" ]; then
|
if [ -z "$NEXT_PUBLIC_SOURCEBOT_VERSION" ] && [ ! -z "$SOURCEBOT_VERSION" ]; then
|
||||||
export NEXT_PUBLIC_SOURCEBOT_VERSION="$SOURCEBOT_VERSION"
|
export NEXT_PUBLIC_SOURCEBOT_VERSION="$SOURCEBOT_VERSION"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
find /app/packages/web/public /app/packages/web/.next -type f -name "*.js" |
|
# Iterate over all .js files in .next & public, making substitutions for the `BAKED_` sentinal values
|
||||||
while read file; do
|
# with their actual desired runtime value.
|
||||||
|
find /app/packages/web/public /app/packages/web/.next -type f -name "*.js" |
|
||||||
|
while read file; do
|
||||||
sed -i "s|BAKED_NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED|${NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED}|g" "$file"
|
sed -i "s|BAKED_NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED|${NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED}|g" "$file"
|
||||||
sed -i "s|BAKED_NEXT_PUBLIC_SOURCEBOT_VERSION|${NEXT_PUBLIC_SOURCEBOT_VERSION}|g" "$file"
|
sed -i "s|BAKED_NEXT_PUBLIC_SOURCEBOT_VERSION|${NEXT_PUBLIC_SOURCEBOT_VERSION}|g" "$file"
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Update specifically NEXT_PUBLIC_DOMAIN_SUB_PATH w/o requiring a rebuild.
|
||||||
|
# Ultimately, the DOMAIN_SUB_PATH sets the `basePath` param in the next.config.mjs.
|
||||||
|
# Similar to above, we pass in a `BAKED_` sentinal value into next.config.mjs at build
|
||||||
|
# time. Unlike above, the `basePath` configuration is set in files other than just javascript
|
||||||
|
# code (e.g., manifest files, css files, etc.), so this section has subtle differences.
|
||||||
|
#
|
||||||
|
# @see: https://nextjs.org/docs/app/api-reference/next-config-js/basePath
|
||||||
|
# @see: https://phase.dev/blog/nextjs-public-runtime-variables/
|
||||||
|
{
|
||||||
|
if [ ! -z "$DOMAIN_SUB_PATH" ]; then
|
||||||
|
# If the sub-path is "/", this creates problems with certain replacements. For example:
|
||||||
|
# /BAKED_NEXT_PUBLIC_DOMAIN_SUB_PATH/_next/image -> //_next/image (notice the double slash...)
|
||||||
|
# To get around this, we default to an empty sub-path, which is the default when no sub-path is defined.
|
||||||
|
if [ "$DOMAIN_SUB_PATH" = "/" ]; then
|
||||||
|
DOMAIN_SUB_PATH=""
|
||||||
|
|
||||||
|
# Otherwise, we need to ensure that the sub-path starts with a slash, since this is a requirement
|
||||||
|
# for the basePath property. For example, assume DOMAIN_SUB_PATH=/bot, then:
|
||||||
|
# /BAKED_NEXT_PUBLIC_DOMAIN_SUB_PATH/_next/image -> /bot/_next/image
|
||||||
|
elif [[ ! "$DOMAIN_SUB_PATH" =~ ^/ ]]; then
|
||||||
|
DOMAIN_SUB_PATH="/$DOMAIN_SUB_PATH"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$DOMAIN_SUB_PATH" ]; then
|
||||||
|
echo -e "\e[34m[Info] DOMAIN_SUB_PATH was set to "$DOMAIN_SUB_PATH". Overriding default path.\e[0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always set NEXT_PUBLIC_DOMAIN_SUB_PATH to DOMAIN_SUB_PATH (even if it is empty!!)
|
||||||
|
export NEXT_PUBLIC_DOMAIN_SUB_PATH="$DOMAIN_SUB_PATH"
|
||||||
|
|
||||||
|
# Iterate over _all_ files in the web directory, making substitutions for the `BAKED_` sentinal values
|
||||||
|
# with their actual desired runtime value.
|
||||||
|
find /app/packages/web -type f |
|
||||||
|
while read file; do
|
||||||
|
# @note: the leading "/" is required here as it is included at build time. See Dockerfile.
|
||||||
|
sed -i "s|/BAKED_NEXT_PUBLIC_DOMAIN_SUB_PATH|${NEXT_PUBLIC_DOMAIN_SUB_PATH}|g" "$file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Run supervisord
|
||||||
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
exec supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
@ -21,6 +21,11 @@ const nextConfig = {
|
||||||
},
|
},
|
||||||
// This is required to support PostHog trailing slash API requests
|
// This is required to support PostHog trailing slash API requests
|
||||||
skipTrailingSlashRedirect: true,
|
skipTrailingSlashRedirect: true,
|
||||||
|
|
||||||
|
// @note: this is evaluated at build time.
|
||||||
|
...(process.env.NEXT_PUBLIC_DOMAIN_SUB_PATH ? {
|
||||||
|
basePath: process.env.NEXT_PUBLIC_DOMAIN_SUB_PATH,
|
||||||
|
} : {})
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { NEXT_PUBLIC_DOMAIN_SUB_PATH } from "@/lib/environment.client";
|
||||||
import { fileSourceResponseSchema, listRepositoriesResponseSchema, searchResponseSchema } from "@/lib/schemas";
|
import { fileSourceResponseSchema, listRepositoriesResponseSchema, searchResponseSchema } from "@/lib/schemas";
|
||||||
import { FileSourceRequest, FileSourceResponse, ListRepositoriesResponse, SearchRequest, SearchResponse } from "@/lib/types";
|
import { FileSourceRequest, FileSourceResponse, ListRepositoriesResponse, SearchRequest, SearchResponse } from "@/lib/types";
|
||||||
|
|
||||||
export const search = async (body: SearchRequest): Promise<SearchResponse> => {
|
export const search = async (body: SearchRequest): Promise<SearchResponse> => {
|
||||||
const result = await fetch(`/api/search`, {
|
const path = resolveServerPath("/api/search");
|
||||||
|
const result = await fetch(path, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
@ -14,7 +18,8 @@ export const search = async (body: SearchRequest): Promise<SearchResponse> => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchFileSource = async (body: FileSourceRequest): Promise<FileSourceResponse> => {
|
export const fetchFileSource = async (body: FileSourceRequest): Promise<FileSourceResponse> => {
|
||||||
const result = await fetch(`/api/source`, {
|
const path = resolveServerPath("/api/source");
|
||||||
|
const result = await fetch(path, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
@ -26,7 +31,8 @@ export const fetchFileSource = async (body: FileSourceRequest): Promise<FileSour
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRepos = async (): Promise<ListRepositoriesResponse> => {
|
export const getRepos = async (): Promise<ListRepositoriesResponse> => {
|
||||||
const result = await fetch('/api/repos', {
|
const path = resolveServerPath("/api/repos");
|
||||||
|
const result = await fetch(path, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
@ -35,3 +41,12 @@ export const getRepos = async (): Promise<ListRepositoriesResponse> => {
|
||||||
|
|
||||||
return listRepositoriesResponseSchema.parse(result);
|
return listRepositoriesResponseSchema.parse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a subpath to a api route on the server (e.g., /api/search),
|
||||||
|
* returns the full path to that route on the server, taking into account
|
||||||
|
* the base path (if any).
|
||||||
|
*/
|
||||||
|
export const resolveServerPath = (path: string) => {
|
||||||
|
return `${NEXT_PUBLIC_DOMAIN_SUB_PATH}${path}`;
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,15 @@
|
||||||
import { NEXT_PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_POSTHOG_UI_HOST, NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED } from '@/lib/environment.client'
|
import { NEXT_PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_POSTHOG_UI_HOST, NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED } from '@/lib/environment.client'
|
||||||
import posthog from 'posthog-js'
|
import posthog from 'posthog-js'
|
||||||
import { PostHogProvider } from 'posthog-js/react'
|
import { PostHogProvider } from 'posthog-js/react'
|
||||||
|
import { resolveServerPath } from './api/(client)/client'
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
if (!NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED) {
|
if (!NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED) {
|
||||||
|
// @see next.config.mjs for path rewrites to the "/ingest" route.
|
||||||
|
const posthogHostPath = resolveServerPath('/ingest');
|
||||||
|
|
||||||
posthog.init(NEXT_PUBLIC_POSTHOG_KEY!, {
|
posthog.init(NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
api_host: "/ingest",
|
api_host: posthogHostPath,
|
||||||
ui_host: NEXT_PUBLIC_POSTHOG_UI_HOST,
|
ui_host: NEXT_PUBLIC_POSTHOG_UI_HOST,
|
||||||
person_profiles: 'identified_only',
|
person_profiles: 'identified_only',
|
||||||
capture_pageview: false, // Disable automatic pageview capture
|
capture_pageview: false, // Disable automatic pageview capture
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,4 @@ export const NEXT_PUBLIC_POSTHOG_UI_HOST = getEnv(process.env.NEXT_PUBLIC_POSTHO
|
||||||
export const NEXT_PUBLIC_POSTHOG_ASSET_HOST = getEnv(process.env.NEXT_PUBLIC_POSTHOG_ASSET_HOST);
|
export const NEXT_PUBLIC_POSTHOG_ASSET_HOST = getEnv(process.env.NEXT_PUBLIC_POSTHOG_ASSET_HOST);
|
||||||
export const NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED = getEnvBoolean(process.env.NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED, false);
|
export const NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED = getEnvBoolean(process.env.NEXT_PUBLIC_SOURCEBOT_TELEMETRY_DISABLED, false);
|
||||||
export const NEXT_PUBLIC_SOURCEBOT_VERSION = getEnv(process.env.NEXT_PUBLIC_SOURCEBOT_VERSION, "unknown");
|
export const NEXT_PUBLIC_SOURCEBOT_VERSION = getEnv(process.env.NEXT_PUBLIC_SOURCEBOT_VERSION, "unknown");
|
||||||
|
export const NEXT_PUBLIC_DOMAIN_SUB_PATH = getEnv(process.env.NEXT_PUBLIC_DOMAIN_SUB_PATH, "");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue