Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
454c124e1e | ||
|
|
1cf0b493d3 | ||
|
|
9c5c5bf4ca | ||
|
|
1a1a45bac4 | ||
|
|
e23d25520d | ||
|
|
20e016198c | ||
|
|
6df2dd8b23 | ||
|
|
e21102664e | ||
|
|
d31b0eaddc | ||
|
|
f53ad4de5c | ||
|
|
053d7d668d | ||
|
|
21e3ed2b39 | ||
|
|
16ca4e9293 | ||
|
|
75f82be88d | ||
|
|
22f6a02b08 | ||
|
|
11aa1dbbb1 | ||
|
|
d961d85a28 | ||
|
|
d0c1ad5144 | ||
|
|
0d30b2fe83 | ||
|
|
f33bae6683 | ||
|
|
eaa0df125b | ||
|
|
b0e01b7127 | ||
|
|
2a421e7406 | ||
|
|
23150b68db | ||
|
|
e5c46010a4 | ||
|
|
b2bf68d7a4 | ||
|
|
31cec4f5c9 | ||
|
|
84a0ad8dfb | ||
|
|
69466fd43b | ||
|
|
324e078c85 | ||
|
|
7385fc4529 | ||
|
|
66d1fa427f | ||
|
|
bee396a433 | ||
|
|
8727a52931 | ||
|
|
ed5c076a5a | ||
|
|
db5c575ae0 | ||
|
|
2a0f482578 | ||
|
|
c041cf371a | ||
|
|
c6daf09cd2 | ||
|
|
7296e2e012 | ||
|
|
43bf176ef7 |
+11
-1
@@ -55,6 +55,7 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
|
||||
# Auth, optional configuration
|
||||
# AUTH_DOMAINS_WITH_SSO_ENFORCEMENT=domain1.com,domain2.com
|
||||
# AUTH_IGNORE_ACCOUNT_FIELDS=foo,bar
|
||||
# AUTH_DISABLE_USERNAME_PASSWORD=true
|
||||
# AUTH_DISABLE_SIGNUP=true
|
||||
# AUTH_SESSION_MAX_AGE=43200 # 30 days in minutes (default)
|
||||
@@ -67,6 +68,10 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
# AUTH_GITHUB_CLIENT_ID=
|
||||
# AUTH_GITHUB_CLIENT_SECRET=
|
||||
# AUTH_GITHUB_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_GITHUB_ENTERPRISE_CLIENT_ID=
|
||||
# AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET=
|
||||
# AUTH_GITHUB_ENTERPRISE_BASE_URL=
|
||||
# AUTH_GITHUB_ENTERPRISE_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_GITLAB_CLIENT_ID=
|
||||
# AUTH_GITLAB_CLIENT_SECRET=
|
||||
# AUTH_GITLAB_ALLOW_ACCOUNT_LINKING=false
|
||||
@@ -87,12 +92,17 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
# AUTH_COGNITO_CLIENT_SECRET=
|
||||
# AUTH_COGNITO_ISSUER=
|
||||
# AUTH_COGNITO_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_KEYCLOAK_CLIENT_ID=
|
||||
# AUTH_KEYCLOAK_CLIENT_SECRET=
|
||||
# AUTH_KEYCLOAK_ISSUER=
|
||||
# AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_CUSTOM_CLIENT_ID=
|
||||
# AUTH_CUSTOM_CLIENT_SECRET=
|
||||
# AUTH_CUSTOM_ISSUER=
|
||||
# AUTH_CUSTOM_NAME=
|
||||
# AUTH_CUSTOM_SCOPE="openid email profile" # optional
|
||||
# AUTH_CUSTOM_ALLOW_ACCOUNT_LINKING=false
|
||||
# AUTH_CUSTOM_ID_TOKEN=false # optional, default is true
|
||||
|
||||
# Transactional email, optional
|
||||
# Defines the email address to use as the from address.
|
||||
@@ -245,4 +255,4 @@ OTEL_SERVICE_NAME="langfuse"
|
||||
# LANGFUSE_ASYNC_INGESTION_PROCESSING="true"
|
||||
# QUEUE_CONSUMER_LEGACY_INGESTION_QUEUE_IS_ENABLED="true"
|
||||
|
||||
## END Langfuse V3 Ingestion
|
||||
## END Langfuse V3 Ingestion
|
||||
|
||||
@@ -3,9 +3,14 @@ name: Codespell
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches:
|
||||
- "main"
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
branches:
|
||||
- "**"
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install golang-migrate for Clickhouse migrations
|
||||
run: |
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
sudo mv migrate /usr/bin/migrate
|
||||
which migrate
|
||||
- uses: pnpm/action-setup@v3
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install golang-migrate for Clickhouse migrations
|
||||
run: |
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
sudo mv migrate /usr/bin/migrate
|
||||
which migrate
|
||||
- uses: pnpm/action-setup@v3
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
pnpm install
|
||||
- name: Install golang-migrate for Clickhouse migrations
|
||||
run: |
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
sudo mv migrate /usr/bin/migrate
|
||||
which migrate
|
||||
- name: Load default env
|
||||
@@ -330,7 +330,7 @@ jobs:
|
||||
pnpm install
|
||||
- name: Install golang-migrate for Clickhouse migrations
|
||||
run: |
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.16.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.linux-amd64.tar.gz | tar xvz
|
||||
sudo mv migrate /usr/bin/migrate
|
||||
which migrate
|
||||
- name: Load default env
|
||||
@@ -487,3 +487,11 @@ jobs:
|
||||
platforms: |
|
||||
linux/amd64
|
||||
${{ startsWith(github.ref, 'refs/tags/') && 'linux/arm64' || '' }}
|
||||
- name: Notify Slack
|
||||
uses: ravsamhq/notify-slack-action@v2
|
||||
if: always()
|
||||
with:
|
||||
status: ${{ job.status }}
|
||||
notify_when: "failure"
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
+4
-3
@@ -27,8 +27,9 @@
|
||||
"@langfuse/shared": "workspace:*",
|
||||
"@opentelemetry/api": ">=1.0.0 <1.10.0",
|
||||
"axios": "^1.7.7",
|
||||
"next": "^14.2.15",
|
||||
"next-auth": "^4.24.7",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"next": "^14.2.21",
|
||||
"next-auth": "^4.24.11",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -47,7 +48,7 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jsonpath-plus": "10.0.7"
|
||||
"jsonpath-plus": "10.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "langfuse",
|
||||
"version": "2.92.0",
|
||||
"version": "2.95.5",
|
||||
"author": "engineering@langfuse.com",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@@ -83,7 +83,12 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jsonpath-plus": "10.0.7"
|
||||
"jsonpath-plus": "10.3.0",
|
||||
"nanoid": "^3.3.8",
|
||||
"katex": "^0.16.21"
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"next-auth@4.24.11": "patches/next-auth@4.24.11.patch"
|
||||
}
|
||||
},
|
||||
"packageManager": "pnpm@9.5.0"
|
||||
|
||||
@@ -76,12 +76,13 @@
|
||||
"dd-trace": "^5.23.1",
|
||||
"decimal.js": "^10.4.3",
|
||||
"exponential-backoff": "^3.1.1",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"ioredis": "^5.4.1",
|
||||
"kysely": "^0.27.4",
|
||||
"langchain": "^0.3.6",
|
||||
"langfuse-langchain": "3.30.3",
|
||||
"lodash": "^4.17.21",
|
||||
"next-auth": "^4.24.7",
|
||||
"next-auth": "^4.24.11",
|
||||
"nodemailer": "^6.9.15",
|
||||
"prisma-extension-kysely": "^2.1.0",
|
||||
"uuid": "^9.0.1",
|
||||
@@ -120,7 +121,7 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jsonpath-plus": "10.0.7"
|
||||
"jsonpath-plus": "10.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ export function CustomSSOProvider<P extends CustomSSOUser>(
|
||||
wellKnown: `${options.issuer}/.well-known/openid-configuration`,
|
||||
authorization: { params: { scope: "openid email profile" } }, // overridden by options.authorization to be able to set custom scopes, deep merged with this default
|
||||
checks: ["pkce", "state"],
|
||||
idToken: true,
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers/oauth";
|
||||
import type { GithubProfile, GithubEmail } from "next-auth/providers/github";
|
||||
|
||||
export function GitHubEnterpriseProvider<P extends GithubProfile>(
|
||||
options: OAuthUserConfig<P> & {
|
||||
enterprise?: {
|
||||
baseUrl?: string;
|
||||
};
|
||||
}
|
||||
): OAuthConfig<P> {
|
||||
const baseUrl = options?.enterprise?.baseUrl ?? "https://github.com"
|
||||
const apiBaseUrl = options?.enterprise?.baseUrl
|
||||
? `${options?.enterprise?.baseUrl}/api/v3`
|
||||
: "https://api.github.com"
|
||||
|
||||
return {
|
||||
id: "github-enterprise",
|
||||
name: "GitHub Enterprise",
|
||||
type: "oauth",
|
||||
authorization: {
|
||||
url: `${baseUrl}/login/oauth/authorize`,
|
||||
params: { scope: "read:user user:email" },
|
||||
},
|
||||
token: `${baseUrl}/login/oauth/access_token`,
|
||||
userinfo: {
|
||||
url: `${apiBaseUrl}/user`,
|
||||
async request({ client, tokens }) {
|
||||
const profile = await client.userinfo(tokens.access_token!)
|
||||
|
||||
if (!profile.email) {
|
||||
// If the user does not have a public email, get another via the GitHub API
|
||||
// See https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
const res = await fetch(`${apiBaseUrl}/user/emails`, {
|
||||
headers: { Authorization: `token ${tokens.access_token}` },
|
||||
})
|
||||
|
||||
if (res.ok) {
|
||||
const emails: GithubEmail[] = await res.json()
|
||||
profile.email = (emails.find((e) => e.primary) ?? emails[0]).email
|
||||
}
|
||||
}
|
||||
|
||||
return profile
|
||||
},
|
||||
},
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.id.toString(),
|
||||
name: profile.name ?? profile.login,
|
||||
email: profile.email,
|
||||
image: profile.avatar_url,
|
||||
}
|
||||
},
|
||||
style: {
|
||||
logo: "https://raw.githubusercontent.com/nextauthjs/next-auth/main/packages/next-auth/provider-logos/github.svg",
|
||||
logoDark:
|
||||
"https://raw.githubusercontent.com/nextauthjs/next-auth/main/packages/next-auth/provider-logos/github-dark.svg",
|
||||
bg: "#fff",
|
||||
bgDark: "#000",
|
||||
text: "#000",
|
||||
textDark: "#fff",
|
||||
},
|
||||
options,
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export * from "./services/PromptService";
|
||||
export * from "./services/traces-ui-table-service";
|
||||
export * from "./auth/apiKeys";
|
||||
export * from "./auth/customSsoProvider";
|
||||
export * from "./auth/gitHubEnterpriseProvider";
|
||||
export * from "./llm/fetchLLMCompletion";
|
||||
export * from "./llm/types";
|
||||
export * from "./utils/DatabaseReadStream";
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
diff --git a/core/lib/oauth/client.js b/core/lib/oauth/client.js
|
||||
index 52c51eb6ff422dc0899ccec31baf3fa39e42eeae..bc50c35bb617d0e86b68ca42f64d44b475ba4abb 100644
|
||||
--- a/core/lib/oauth/client.js
|
||||
+++ b/core/lib/oauth/client.js
|
||||
@@ -1,5 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
+var HttpsProxyAgent = require('https-proxy-agent').HttpsProxyAgent;
|
||||
+
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
@@ -7,7 +9,12 @@ exports.openidClient = openidClient;
|
||||
var _openidClient = require("openid-client");
|
||||
async function openidClient(options) {
|
||||
const provider = options.provider;
|
||||
- if (provider.httpOptions) _openidClient.custom.setHttpOptionsDefaults(provider.httpOptions);
|
||||
+ let httpOptions = {};
|
||||
+ if (provider.httpOptions) httpOptions = { ...provider.httpOptions };
|
||||
+ if (process.env.AUTH_HTTPS_PROXY || process.env.AUTH_HTTP_PROXY) {
|
||||
+ httpOptions.agent = new HttpsProxyAgent(process.env.AUTH_HTTPS_PROXY || process.env.AUTH_HTTP_PROXY);
|
||||
+ }
|
||||
+ _openidClient.custom.setHttpOptionsDefaults(httpOptions);
|
||||
let issuer;
|
||||
if (provider.wellKnown) {
|
||||
issuer = await _openidClient.Issuer.discover(provider.wellKnown);
|
||||
Generated
+1200
-1065
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -109,7 +109,7 @@ RUN adduser --system --uid 1001 nextjs
|
||||
RUN npm install -g --no-package-lock --no-save prisma@5.22.0
|
||||
|
||||
RUN MIGRATE_TARGET_ARCH=$(echo ${TARGETPLATFORM:-linux/amd64} | sed 's/\//-/g') && \
|
||||
wget -q -O- https://github.com/golang-migrate/migrate/releases/download/v4.18.0/migrate.$MIGRATE_TARGET_ARCH.tar.gz | tar xvz && \
|
||||
wget -q -O- https://github.com/golang-migrate/migrate/releases/download/v4.18.2/migrate.$MIGRATE_TARGET_ARCH.tar.gz | tar xvz && \
|
||||
mv migrate /usr/bin/migrate
|
||||
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/web/next.config.mjs .
|
||||
|
||||
+6
-1
@@ -12,11 +12,16 @@ if [ -z "$DATABASE_URL" ]; then
|
||||
echo "Error: Required database environment variables are not set. Provide a postgres url for DATABASE_URL."
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$DATABASE_ARGS" ]; then
|
||||
# Append ARGS to DATABASE_URL
|
||||
DATABASE_URL="${DATABASE_URL}?$DATABASE_ARGS"
|
||||
export DATABASE_URL
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set DIRECT_URL to the value of DATABASE_URL if it is not set, required for migrations
|
||||
if [ -z "$DIRECT_URL" ]; then
|
||||
export DIRECT_URL=$DATABASE_URL
|
||||
export DIRECT_URL="${DATABASE_URL}"
|
||||
fi
|
||||
|
||||
# Always execute the postgres migration, except when disabled.
|
||||
|
||||
+24
-4
@@ -28,6 +28,9 @@ const cspHeader = `
|
||||
${env.SENTRY_CSP_REPORT_URI ? `report-uri ${env.SENTRY_CSP_REPORT_URI}; report-to csp-endpoint;` : ""}
|
||||
`;
|
||||
|
||||
// Match rules for Hugging Face
|
||||
const huggingFaceHosts = ["huggingface.co", ".*\\.hf\\.space$"];
|
||||
|
||||
const reportToHeader = {
|
||||
key: "Report-To",
|
||||
value: JSON.stringify({
|
||||
@@ -58,6 +61,7 @@ const nextConfig = {
|
||||
"kysely",
|
||||
],
|
||||
},
|
||||
staticPageGenerationTimeout: 500, // 5 minutes - default 60 seconds.
|
||||
poweredByHeader: false,
|
||||
basePath: env.NEXT_PUBLIC_BASE_PATH,
|
||||
|
||||
@@ -78,10 +82,6 @@ const nextConfig = {
|
||||
{
|
||||
source: "/:path*",
|
||||
headers: [
|
||||
{
|
||||
key: "x-frame-options",
|
||||
value: "SAMEORIGIN",
|
||||
},
|
||||
{
|
||||
key: "X-Content-Type-Options",
|
||||
value: "nosniff",
|
||||
@@ -97,6 +97,21 @@ const nextConfig = {
|
||||
...(env.SENTRY_CSP_REPORT_URI ? [reportToHeader] : []),
|
||||
],
|
||||
},
|
||||
{
|
||||
source: "/:path*",
|
||||
headers: [
|
||||
{
|
||||
key: "x-frame-options",
|
||||
value: "SAMEORIGIN",
|
||||
},
|
||||
],
|
||||
// Disable x-frame-options on Hugging Face to allow for embedded use of Langfuse
|
||||
missing: huggingFaceHosts.map((host) => ({
|
||||
type: "host",
|
||||
value: host,
|
||||
})),
|
||||
},
|
||||
// CSP header
|
||||
{
|
||||
source: "/:path((?!api).*)*",
|
||||
headers: [
|
||||
@@ -105,6 +120,11 @@ const nextConfig = {
|
||||
value: cspHeader.replace(/\n/g, ""),
|
||||
},
|
||||
],
|
||||
// Disable CSP on Hugging Face to allow for embedded use of Langfuse
|
||||
missing: huggingFaceHosts.map((host) => ({
|
||||
type: "host",
|
||||
value: host,
|
||||
})),
|
||||
},
|
||||
// Required to check authentication status from langfuse.com
|
||||
...(env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION !== undefined
|
||||
|
||||
+8
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "2.92.0",
|
||||
"version": "2.95.5",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -26,7 +26,7 @@
|
||||
"@appsignal/opentelemetry-instrumentation-bullmq": "^0.7.3",
|
||||
"@baselime/trpc-opentelemetry-middleware": "^0.1.2",
|
||||
"@codemirror/lang-json": "^6.0.1",
|
||||
"@codemirror/lint": "^6.8.0",
|
||||
"@codemirror/lint": "^6.4.2",
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/modifiers": "^7.0.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
@@ -83,7 +83,7 @@
|
||||
"@remixicon/react": "^4.2.0",
|
||||
"@repo/eslint-config": "workspace:*",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"@sentry/nextjs": "^8.39.0",
|
||||
"@sentry/nextjs": "^8.52.0",
|
||||
"@t3-oss/env-nextjs": "^0.11.1",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
@@ -107,8 +107,9 @@
|
||||
"date-fns": "^3.3.1",
|
||||
"dd-trace": "^5.23.1",
|
||||
"decimal.js": "^10.4.3",
|
||||
"dompurify": "^3.1.5",
|
||||
"dompurify": "^3.2.4",
|
||||
"graphql": "^16.9.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"ioredis": "^5.4.1",
|
||||
"ip-address": "^9.0.5",
|
||||
"js-tiktoken": "^1.0.15",
|
||||
@@ -116,8 +117,8 @@
|
||||
"langchain": "^0.3.6",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.447.0",
|
||||
"next": "^14.2.15",
|
||||
"next-auth": "^4.24.7",
|
||||
"next": "^14.2.21",
|
||||
"next-auth": "^4.24.11",
|
||||
"next-query-params": "^5.0.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"posthog-js": "^1.176.0",
|
||||
@@ -192,7 +193,7 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jsonpath-plus": "10.0.7"
|
||||
"jsonpath-plus": "10.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 34 KiB |
@@ -57,6 +57,7 @@ const unauthenticatedPaths: string[] = [
|
||||
"/auth/sign-in",
|
||||
"/auth/sign-up",
|
||||
"/auth/error",
|
||||
"/auth/hf-spaces",
|
||||
];
|
||||
// auth or unauthed
|
||||
const publishablePaths: string[] = [
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v2.92.0";
|
||||
export const VERSION = "v2.95.5";
|
||||
|
||||
@@ -69,7 +69,7 @@ import { showSuccessToast } from "@/src/features/notifications/showSuccessToast"
|
||||
const formSchema = z.object({
|
||||
scoreName: z.string(),
|
||||
target: z.string(),
|
||||
filter: z.array(singleFilter).nullable(), // re-using the filter type from the tables
|
||||
filter: z.array(singleFilter).nullable(), // reusing the filter type from the tables
|
||||
mapping: z.array(wipVariableMapping),
|
||||
sampling: z.coerce.number().gt(0).lte(1),
|
||||
delay: z.coerce.number().optional().default(10),
|
||||
|
||||
@@ -35,7 +35,7 @@ const APIEvaluatorSchema = z.object({
|
||||
evalTemplateId: z.string(),
|
||||
scoreName: z.string(),
|
||||
targetObject: z.string(),
|
||||
filter: z.array(singleFilter).nullable(), // re-using the filter type from the tables
|
||||
filter: z.array(singleFilter).nullable(), // reusing the filter type from the tables
|
||||
variableMapping: z.array(variableMapping),
|
||||
sampling: z.instanceof(Prisma.Decimal),
|
||||
delay: z.number(),
|
||||
@@ -91,7 +91,7 @@ const CreateEvalJobSchema = z.object({
|
||||
evalTemplateId: z.string(),
|
||||
scoreName: z.string().min(1),
|
||||
target: z.string(),
|
||||
filter: z.array(singleFilter).nullable(), // re-using the filter type from the tables
|
||||
filter: z.array(singleFilter).nullable(), // reusing the filter type from the tables
|
||||
mapping: z.array(variableMapping),
|
||||
sampling: z.number().gt(0).lte(1),
|
||||
delay: z.number().gte(0).default(DEFAULT_TRACE_JOB_DELAY), // 10 seconds default
|
||||
|
||||
@@ -28,6 +28,20 @@ export const GithubProviderSchema = base.extend({
|
||||
.nullish(),
|
||||
});
|
||||
|
||||
export const GithubEnterpriseProviderSchema = base.extend({
|
||||
authProvider: z.literal("github-enterprise"),
|
||||
authConfig: z
|
||||
.object({
|
||||
clientId: z.string(),
|
||||
clientSecret: z.string(),
|
||||
enterprise: z.object({
|
||||
baseUrl: z.string().url(),
|
||||
}),
|
||||
allowDangerousEmailAccountLinking: z.boolean().optional().default(false),
|
||||
})
|
||||
.nullish(),
|
||||
});
|
||||
|
||||
export const GitlabProviderSchema = base.extend({
|
||||
authProvider: z.literal("gitlab"),
|
||||
authConfig: z
|
||||
@@ -88,6 +102,18 @@ export const CognitoProviderSchema = base.extend({
|
||||
.nullish(),
|
||||
});
|
||||
|
||||
export const KeycloakProviderSchema = base.extend({
|
||||
authProvider: z.literal("keycloak"),
|
||||
authConfig: z
|
||||
.object({
|
||||
clientId: z.string(),
|
||||
clientSecret: z.string(),
|
||||
issuer: z.string(),
|
||||
allowDangerousEmailAccountLinking: z.boolean().optional().default(false),
|
||||
})
|
||||
.nullish(),
|
||||
});
|
||||
|
||||
export const CustomProviderSchema = base.extend({
|
||||
authProvider: z.literal("custom"),
|
||||
authConfig: z
|
||||
@@ -97,6 +123,7 @@ export const CustomProviderSchema = base.extend({
|
||||
clientSecret: z.string(),
|
||||
issuer: z.string(),
|
||||
scope: z.string().nullish(),
|
||||
idToken: z.boolean().optional().default(true),
|
||||
allowDangerousEmailAccountLinking: z.boolean().optional().default(false),
|
||||
})
|
||||
.nullish(),
|
||||
@@ -104,21 +131,27 @@ export const CustomProviderSchema = base.extend({
|
||||
|
||||
export type GoogleProviderSchema = z.infer<typeof GoogleProviderSchema>;
|
||||
export type GithubProviderSchema = z.infer<typeof GithubProviderSchema>;
|
||||
export type GithubEnterpriseProviderSchema = z.infer<
|
||||
typeof GithubEnterpriseProviderSchema
|
||||
>;
|
||||
export type GitlabProviderSchema = z.infer<typeof GitlabProviderSchema>;
|
||||
export type Auth0ProviderSchema = z.infer<typeof Auth0ProviderSchema>;
|
||||
export type OktaProviderSchema = z.infer<typeof OktaProviderSchema>;
|
||||
export type AzureAdProviderSchema = z.infer<typeof AzureAdProviderSchema>;
|
||||
export type CognitoProviderSchema = z.infer<typeof CognitoProviderSchema>;
|
||||
export type KeycloakProviderSchema = z.infer<typeof KeycloakProviderSchema>;
|
||||
export type CustomProviderSchema = z.infer<typeof CustomProviderSchema>;
|
||||
|
||||
export const SsoProviderSchema = z.discriminatedUnion("authProvider", [
|
||||
GoogleProviderSchema,
|
||||
GithubProviderSchema,
|
||||
GithubEnterpriseProviderSchema,
|
||||
GitlabProviderSchema,
|
||||
Auth0ProviderSchema,
|
||||
OktaProviderSchema,
|
||||
AzureAdProviderSchema,
|
||||
CognitoProviderSchema,
|
||||
KeycloakProviderSchema,
|
||||
CustomProviderSchema,
|
||||
]);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import GitHubProvider from "next-auth/providers/github";
|
||||
import GitLabProvider from "next-auth/providers/gitlab";
|
||||
import OktaProvider from "next-auth/providers/okta";
|
||||
import CognitoProvider from "next-auth/providers/cognito";
|
||||
import KeycloakProvider from "next-auth/providers/keycloak";
|
||||
import Auth0Provider from "next-auth/providers/auth0";
|
||||
import AzureADProvider from "next-auth/providers/azure-ad";
|
||||
import { isEeEnabled } from "@/src/ee/utils/isEeEnabled";
|
||||
@@ -12,6 +13,7 @@ import { decrypt } from "@langfuse/shared/encryption";
|
||||
import { SsoProviderSchema } from "./types";
|
||||
import {
|
||||
CustomSSOProvider,
|
||||
GitHubEnterpriseProvider,
|
||||
logger,
|
||||
traceException,
|
||||
} from "@langfuse/shared/src/server";
|
||||
@@ -188,6 +190,12 @@ const dbToNextAuthProvider = (provider: SsoProviderSchema): Provider | null => {
|
||||
...provider.authConfig,
|
||||
clientSecret: decrypt(provider.authConfig.clientSecret),
|
||||
});
|
||||
else if (provider.authProvider === "keycloak")
|
||||
return KeycloakProvider({
|
||||
id: getAuthProviderIdForSsoConfig(provider), // use the domain as the provider id as we use domain-specific credentials
|
||||
...provider.authConfig,
|
||||
clientSecret: decrypt(provider.authConfig.clientSecret),
|
||||
});
|
||||
else if (provider.authProvider === "custom")
|
||||
return CustomSSOProvider({
|
||||
id: getAuthProviderIdForSsoConfig(provider), // use the domain as the provider id as we use domain-specific credentials
|
||||
@@ -197,6 +205,15 @@ const dbToNextAuthProvider = (provider: SsoProviderSchema): Provider | null => {
|
||||
params: { scope: provider.authConfig.scope ?? "openid email profile" },
|
||||
},
|
||||
});
|
||||
else if (provider.authProvider === "github-enterprise")
|
||||
return GitHubEnterpriseProvider({
|
||||
id: getAuthProviderIdForSsoConfig(provider), // use the domain as the provider id as we use domain-specific credentials
|
||||
...provider.authConfig,
|
||||
clientSecret: decrypt(provider.authConfig.clientSecret),
|
||||
enterprise: {
|
||||
baseUrl: provider.authConfig.enterprise.baseUrl,
|
||||
},
|
||||
});
|
||||
else {
|
||||
// Type check to ensure we handle all providers
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
+93
-1
@@ -1,6 +1,26 @@
|
||||
import { z } from "zod";
|
||||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
|
||||
const zAuthMethod = z
|
||||
.enum([
|
||||
"client_secret_basic",
|
||||
"client_secret_post",
|
||||
"client_secret_jwt",
|
||||
"private_key_jwt",
|
||||
"tls_client_auth",
|
||||
"self_signed_tls_client_auth",
|
||||
"none",
|
||||
])
|
||||
.optional()
|
||||
.default("client_secret_basic");
|
||||
|
||||
|
||||
const zAuthChecks = z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((s) => s?.split(",").map((s) => s.trim()))
|
||||
.pipe(z.array(z.enum(["nonce", "none", "pkce", "state"])).optional());
|
||||
|
||||
export const env = createEnv({
|
||||
/**
|
||||
* Specify your server-side environment variables schema here. This way you can ensure the app
|
||||
@@ -46,7 +66,7 @@ export const env = createEnv({
|
||||
LANGFUSE_DEFAULT_PROJECT_ROLE: z
|
||||
.enum(["OWNER", "ADMIN", "MEMBER", "VIEWER"])
|
||||
.optional(),
|
||||
LANGFUSE_CSP_ENFORCE_HTTPS: z.enum(["true", "false"]).optional(),
|
||||
LANGFUSE_CSP_ENFORCE_HTTPS: z.enum(["true", "false"]).optional().default("false"),
|
||||
// Telemetry
|
||||
TELEMETRY_ENABLED: z.enum(["true", "false"]).optional(),
|
||||
// AUTH
|
||||
@@ -54,36 +74,68 @@ export const env = createEnv({
|
||||
AUTH_GOOGLE_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_GOOGLE_ALLOWED_DOMAINS: z.string().optional(),
|
||||
AUTH_GOOGLE_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_GOOGLE_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_GOOGLE_CHECKS: zAuthChecks,
|
||||
AUTH_GITHUB_CLIENT_ID: z.string().optional(),
|
||||
AUTH_GITHUB_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_GITHUB_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_GITHUB_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_GITHUB_CHECKS: zAuthChecks,
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_ID: z.string().optional(),
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_GITHUB_ENTERPRISE_BASE_URL: z.string().optional(),
|
||||
AUTH_GITHUB_ENTERPRISE_ALLOW_ACCOUNT_LINKING: z
|
||||
.enum(["true", "false"])
|
||||
.optional(),
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_GITHUB_ENTERPRISE_CHECKS: zAuthChecks,
|
||||
AUTH_GITLAB_CLIENT_ID: z.string().optional(),
|
||||
AUTH_GITLAB_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_GITLAB_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_GITLAB_ISSUER: z.string().optional(),
|
||||
AUTH_GITLAB_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_GITLAB_CHECKS: zAuthChecks,
|
||||
AUTH_AZURE_AD_CLIENT_ID: z.string().optional(),
|
||||
AUTH_AZURE_AD_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_AZURE_AD_TENANT_ID: z.string().optional(),
|
||||
AUTH_AZURE_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_AZURE_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_AZURE_CHECKS: zAuthChecks,
|
||||
AUTH_OKTA_CLIENT_ID: z.string().optional(),
|
||||
AUTH_OKTA_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_OKTA_ISSUER: z.string().optional(),
|
||||
AUTH_OKTA_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_OKTA_CHECKS: zAuthChecks,
|
||||
AUTH_OKTA_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_AUTH0_CLIENT_ID: z.string().optional(),
|
||||
AUTH_AUTH0_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_AUTH0_ISSUER: z.string().url().optional(),
|
||||
AUTH_AUTH0_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_AUTH0_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_AUTH0_CHECKS: zAuthChecks,
|
||||
AUTH_COGNITO_CLIENT_ID: z.string().optional(),
|
||||
AUTH_COGNITO_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_COGNITO_ISSUER: z.string().url().optional(),
|
||||
AUTH_COGNITO_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_COGNITO_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_COGNITO_CHECKS: zAuthChecks,
|
||||
AUTH_KEYCLOAK_CLIENT_ID: z.string().optional(),
|
||||
AUTH_KEYCLOAK_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_KEYCLOAK_ISSUER: z.string().optional(),
|
||||
AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_KEYCLOAK_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_KEYCLOAK_CHECKS: zAuthChecks,
|
||||
AUTH_CUSTOM_CLIENT_ID: z.string().optional(),
|
||||
AUTH_CUSTOM_CLIENT_SECRET: z.string().optional(),
|
||||
AUTH_CUSTOM_ISSUER: z.string().url().optional(),
|
||||
AUTH_CUSTOM_NAME: z.string().optional(),
|
||||
AUTH_CUSTOM_SCOPE: z.string().optional(),
|
||||
AUTH_CUSTOM_CLIENT_AUTH_METHOD: zAuthMethod,
|
||||
AUTH_CUSTOM_CHECKS: zAuthChecks,
|
||||
AUTH_CUSTOM_ALLOW_ACCOUNT_LINKING: z.enum(["true", "false"]).optional(),
|
||||
AUTH_CUSTOM_ID_TOKEN: z.enum(["true", "false"]).optional(),
|
||||
AUTH_DOMAINS_WITH_SSO_ENFORCEMENT: z.string().optional(),
|
||||
AUTH_IGNORE_ACCOUNT_FIELDS: z.string().optional(),
|
||||
AUTH_DISABLE_USERNAME_PASSWORD: z.enum(["true", "false"]).optional(),
|
||||
AUTH_DISABLE_SIGNUP: z.enum(["true", "false"]).optional(),
|
||||
AUTH_SESSION_MAX_AGE: z.coerce
|
||||
@@ -95,6 +147,8 @@ export const env = createEnv({
|
||||
)
|
||||
.optional()
|
||||
.default(30 * 24 * 60), // default to 30 days
|
||||
AUTH_HTTP_PROXY: z.string().url().optional(),
|
||||
AUTH_HTTPS_PROXY: z.string().url().optional(),
|
||||
// EMAIL
|
||||
EMAIL_FROM_ADDRESS: z.string().optional(),
|
||||
SMTP_CONNECTION_URL: z.string().optional(),
|
||||
@@ -287,47 +341,85 @@ export const env = createEnv({
|
||||
AUTH_GOOGLE_ALLOWED_DOMAINS: process.env.AUTH_GOOGLE_ALLOWED_DOMAINS,
|
||||
AUTH_GOOGLE_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_GOOGLE_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_GOOGLE_CLIENT_AUTH_METHOD: process.env.AUTH_GOOGLE_CLIENT_AUTH_METHOD,
|
||||
AUTH_GOOGLE_CHECKS: process.env.AUTH_GOOGLE_CHECKS,
|
||||
AUTH_GITHUB_CLIENT_ID: process.env.AUTH_GITHUB_CLIENT_ID,
|
||||
AUTH_GITHUB_CLIENT_SECRET: process.env.AUTH_GITHUB_CLIENT_SECRET,
|
||||
AUTH_GITHUB_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_GITHUB_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_GITHUB_CLIENT_AUTH_METHOD: process.env.AUTH_GITHUB_CLIENT_AUTH_METHOD,
|
||||
AUTH_GITHUB_CHECKS: process.env.AUTH_GITHUB_CHECKS,
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_ID:
|
||||
process.env.AUTH_GITHUB_ENTERPRISE_CLIENT_ID,
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET:
|
||||
process.env.AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET,
|
||||
AUTH_GITHUB_ENTERPRISE_BASE_URL:
|
||||
process.env.AUTH_GITHUB_ENTERPRISE_BASE_URL,
|
||||
AUTH_GITHUB_ENTERPRISE_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_GITHUB_ENTERPRISE_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_GITHUB_ENTERPRISE_CLIENT_AUTH_METHOD:
|
||||
process.env.AUTH_GITHUB_ENTERPRISE_CLIENT_AUTH_METHOD,
|
||||
AUTH_GITHUB_ENTERPRISE_CHECKS: process.env.AUTH_GITHUB_ENTERPRISE_CHECKS,
|
||||
AUTH_GITLAB_ISSUER: process.env.AUTH_GITLAB_ISSUER,
|
||||
AUTH_GITLAB_CLIENT_ID: process.env.AUTH_GITLAB_CLIENT_ID,
|
||||
AUTH_GITLAB_CLIENT_SECRET: process.env.AUTH_GITLAB_CLIENT_SECRET,
|
||||
AUTH_GITLAB_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_GITLAB_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_GITLAB_CLIENT_AUTH_METHOD: process.env.AUTH_GITLAB_CLIENT_AUTH_METHOD,
|
||||
AUTH_GITLAB_CHECKS: process.env.AUTH_GITLAB_CHECKS,
|
||||
AUTH_AZURE_AD_CLIENT_ID: process.env.AUTH_AZURE_AD_CLIENT_ID,
|
||||
AUTH_AZURE_AD_CLIENT_SECRET: process.env.AUTH_AZURE_AD_CLIENT_SECRET,
|
||||
AUTH_AZURE_AD_TENANT_ID: process.env.AUTH_AZURE_AD_TENANT_ID,
|
||||
AUTH_AZURE_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_AZURE_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_AZURE_CLIENT_AUTH_METHOD: process.env.AUTH_AZURE_CLIENT_AUTH_METHOD,
|
||||
AUTH_AZURE_CHECKS: process.env.AUTH_AZURE_CHECKS,
|
||||
AUTH_OKTA_CLIENT_ID: process.env.AUTH_OKTA_CLIENT_ID,
|
||||
AUTH_OKTA_CLIENT_SECRET: process.env.AUTH_OKTA_CLIENT_SECRET,
|
||||
AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
|
||||
AUTH_OKTA_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_OKTA_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_OKTA_CLIENT_AUTH_METHOD: process.env.AUTH_OKTA_CLIENT_AUTH_METHOD,
|
||||
AUTH_OKTA_CHECKS: process.env.AUTH_OKTA_CHECKS,
|
||||
AUTH_AUTH0_CLIENT_ID: process.env.AUTH_AUTH0_CLIENT_ID,
|
||||
AUTH_AUTH0_CLIENT_SECRET: process.env.AUTH_AUTH0_CLIENT_SECRET,
|
||||
AUTH_AUTH0_ISSUER: process.env.AUTH_AUTH0_ISSUER,
|
||||
AUTH_AUTH0_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_AUTH0_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_AUTH0_CLIENT_AUTH_METHOD: process.env.AUTH_AUTH0_CLIENT_AUTH_METHOD,
|
||||
AUTH_AUTH0_CHECKS: process.env.AUTH_AUTH0_CHECKS,
|
||||
AUTH_COGNITO_CLIENT_ID: process.env.AUTH_COGNITO_CLIENT_ID,
|
||||
AUTH_COGNITO_CLIENT_SECRET: process.env.AUTH_COGNITO_CLIENT_SECRET,
|
||||
AUTH_COGNITO_ISSUER: process.env.AUTH_COGNITO_ISSUER,
|
||||
AUTH_COGNITO_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_COGNITO_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_COGNITO_CLIENT_AUTH_METHOD: process.env.AUTH_COGNITO_CLIENT_AUTH_METHOD,
|
||||
AUTH_COGNITO_CHECKS: process.env.AUTH_COGNITO_CHECKS,
|
||||
AUTH_KEYCLOAK_CLIENT_ID: process.env.AUTH_KEYCLOAK_CLIENT_ID,
|
||||
AUTH_KEYCLOAK_CLIENT_SECRET: process.env.AUTH_KEYCLOAK_CLIENT_SECRET,
|
||||
AUTH_KEYCLOAK_ISSUER: process.env.AUTH_KEYCLOAK_ISSUER,
|
||||
AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_KEYCLOAK_CLIENT_AUTH_METHOD: process.env.AUTH_KEYCLOAK_CLIENT_AUTH_METHOD,
|
||||
AUTH_KEYCLOAK_CHECKS: process.env.AUTH_KEYCLOAK_CHECKS,
|
||||
AUTH_CUSTOM_CLIENT_ID: process.env.AUTH_CUSTOM_CLIENT_ID,
|
||||
AUTH_CUSTOM_CLIENT_SECRET: process.env.AUTH_CUSTOM_CLIENT_SECRET,
|
||||
AUTH_CUSTOM_ISSUER: process.env.AUTH_CUSTOM_ISSUER,
|
||||
AUTH_CUSTOM_NAME: process.env.AUTH_CUSTOM_NAME,
|
||||
AUTH_CUSTOM_SCOPE: process.env.AUTH_CUSTOM_SCOPE,
|
||||
AUTH_CUSTOM_CLIENT_AUTH_METHOD: process.env.AUTH_CUSTOM_CLIENT_AUTH_METHOD,
|
||||
AUTH_CUSTOM_CHECKS: process.env.AUTH_CUSTOM_CHECKS,
|
||||
AUTH_CUSTOM_ALLOW_ACCOUNT_LINKING:
|
||||
process.env.AUTH_CUSTOM_ALLOW_ACCOUNT_LINKING,
|
||||
AUTH_CUSTOM_ID_TOKEN: process.env.AUTH_CUSTOM_ID_TOKEN,
|
||||
AUTH_IGNORE_ACCOUNT_FIELDS: process.env.AUTH_IGNORE_ACCOUNT_FIELDS,
|
||||
AUTH_DOMAINS_WITH_SSO_ENFORCEMENT:
|
||||
process.env.AUTH_DOMAINS_WITH_SSO_ENFORCEMENT,
|
||||
AUTH_DISABLE_USERNAME_PASSWORD: process.env.AUTH_DISABLE_USERNAME_PASSWORD,
|
||||
AUTH_DISABLE_SIGNUP: process.env.AUTH_DISABLE_SIGNUP,
|
||||
AUTH_SESSION_MAX_AGE: process.env.AUTH_SESSION_MAX_AGE,
|
||||
AUTH_HTTP_PROXY: process.env.AUTH_HTTP_PROXY,
|
||||
AUTH_HTTPS_PROXY: process.env.AUTH_HTTPS_PROXY,
|
||||
// Email
|
||||
EMAIL_FROM_ADDRESS: process.env.EMAIL_FROM_ADDRESS,
|
||||
SMTP_CONNECTION_URL: process.env.SMTP_CONNECTION_URL,
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* When running Langfuse in HuggingFace Spaces, the app needs to be opened in a new tab.
|
||||
* Otherwise, the app will not be able to access the session cookie.
|
||||
*/
|
||||
|
||||
import { Button } from "@/src/components/ui/button";
|
||||
import { LangfuseIcon } from "@/src/components/LangfuseLogo";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import { type GetServerSideProps } from "next";
|
||||
import { env } from "@/src/env.mjs";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { CodeView } from "@/src/components/ui/CodeJsonViewer";
|
||||
|
||||
type PageProps = {
|
||||
deploymentDomain: string;
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
// remove /api/auth from the URL as it needs to be added for custom base url
|
||||
const deploymentDomain = env.NEXTAUTH_URL?.replace("/api/auth", "");
|
||||
return {
|
||||
props: {
|
||||
deploymentDomain,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default function HfSpaces({ deploymentDomain }: PageProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Langfuse on Hugging Face</title>
|
||||
</Head>
|
||||
<div className="flex flex-1 flex-col py-6 sm:min-h-full sm:justify-center sm:px-6 sm:py-12 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<LangfuseIcon />
|
||||
<PlusIcon size={12} className="ml-1" />
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/assets/huggingface-logo.svg"
|
||||
alt="Hugging Face Logo"
|
||||
width={36}
|
||||
height={36}
|
||||
/>
|
||||
</div>
|
||||
<h2 className="mt-4 text-center text-2xl font-bold leading-9 tracking-tight text-primary">
|
||||
Langfuse on Hugging Face
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="mt-14 bg-background px-6 py-10 shadow sm:mx-auto sm:w-full sm:max-w-[480px] sm:rounded-lg sm:px-10">
|
||||
<div className="space-y-8">
|
||||
<CodeView content={deploymentDomain} title="HF Space Host" />
|
||||
|
||||
<Button className="w-full" asChild>
|
||||
<Link
|
||||
href={deploymentDomain}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Open in new tab
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import { env } from "@/src/env.mjs";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { FcGoogle } from "react-icons/fc";
|
||||
import { FaGithub, FaGitlab } from "react-icons/fa";
|
||||
import { SiOkta, SiAuth0, SiAmazoncognito } from "react-icons/si";
|
||||
import { SiOkta, SiAuth0, SiAmazoncognito, SiKeycloak } from "react-icons/si";
|
||||
import { TbBrandAzure, TbBrandOauth } from "react-icons/tb";
|
||||
import { signIn } from "next-auth/react";
|
||||
import Head from "next/head";
|
||||
@@ -46,11 +46,13 @@ export type PageProps = {
|
||||
credentials: boolean;
|
||||
google: boolean;
|
||||
github: boolean;
|
||||
githubEnterprise: boolean;
|
||||
gitlab: boolean;
|
||||
okta: boolean;
|
||||
azureAd: boolean;
|
||||
auth0: boolean;
|
||||
cognito: boolean;
|
||||
keycloak: boolean;
|
||||
custom:
|
||||
| {
|
||||
name: string;
|
||||
@@ -58,6 +60,7 @@ export type PageProps = {
|
||||
| false;
|
||||
sso: boolean;
|
||||
};
|
||||
runningOnHuggingFaceSpaces: boolean;
|
||||
signUpDisabled: boolean;
|
||||
};
|
||||
|
||||
@@ -74,6 +77,10 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
github:
|
||||
env.AUTH_GITHUB_CLIENT_ID !== undefined &&
|
||||
env.AUTH_GITHUB_CLIENT_SECRET !== undefined,
|
||||
githubEnterprise:
|
||||
env.AUTH_GITHUB_ENTERPRISE_CLIENT_ID !== undefined &&
|
||||
env.AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET !== undefined &&
|
||||
env.AUTH_GITHUB_ENTERPRISE_BASE_URL !== undefined,
|
||||
gitlab:
|
||||
env.AUTH_GITLAB_CLIENT_ID !== undefined &&
|
||||
env.AUTH_GITLAB_CLIENT_SECRET !== undefined,
|
||||
@@ -94,6 +101,10 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
env.AUTH_COGNITO_CLIENT_ID !== undefined &&
|
||||
env.AUTH_COGNITO_CLIENT_SECRET !== undefined &&
|
||||
env.AUTH_COGNITO_ISSUER !== undefined,
|
||||
keycloak:
|
||||
env.AUTH_KEYCLOAK_CLIENT_ID !== undefined &&
|
||||
env.AUTH_KEYCLOAK_CLIENT_SECRET !== undefined &&
|
||||
env.AUTH_KEYCLOAK_ISSUER !== undefined,
|
||||
custom:
|
||||
env.AUTH_CUSTOM_CLIENT_ID !== undefined &&
|
||||
env.AUTH_CUSTOM_CLIENT_SECRET !== undefined &&
|
||||
@@ -104,6 +115,10 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
|
||||
sso,
|
||||
},
|
||||
signUpDisabled: env.AUTH_DISABLE_SIGNUP === "true",
|
||||
runningOnHuggingFaceSpaces: env.NEXTAUTH_URL?.replace(
|
||||
"/api/auth",
|
||||
"",
|
||||
).endsWith(".hf.space"),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -165,6 +180,16 @@ export function SSOButtons({
|
||||
Github
|
||||
</Button>
|
||||
)}
|
||||
{authProviders.githubEnterprise && (
|
||||
<Button
|
||||
onClick={() => handleSignIn("github-enterprise")}
|
||||
variant="secondary"
|
||||
loading={providerSigningIn === "github-enterprise"}
|
||||
>
|
||||
<FaGithub className="mr-3" size={18} />
|
||||
Github Enterprise
|
||||
</Button>
|
||||
)}
|
||||
{authProviders.gitlab && (
|
||||
<Button
|
||||
onClick={() => handleSignIn("gitlab")}
|
||||
@@ -215,6 +240,18 @@ export function SSOButtons({
|
||||
Cognito
|
||||
</Button>
|
||||
)}
|
||||
{authProviders.keycloak && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
capture("sign_in:button_click", { provider: "keycloak" });
|
||||
void signIn("keycloak");
|
||||
}}
|
||||
variant="secondary"
|
||||
>
|
||||
<SiKeycloak className="mr-3" size={18} />
|
||||
Keycloak
|
||||
</Button>
|
||||
)}
|
||||
{authProviders.custom && (
|
||||
<Button
|
||||
onClick={() => handleSignIn("custom")}
|
||||
@@ -231,6 +268,33 @@ export function SSOButtons({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to HuggingFace Spaces auth page (/auth/hf-spaces) if running in an iframe on a HuggingFace host.
|
||||
* The iframe detection needs to happen client-side since window/document objects are not available during SSR.
|
||||
* @param runningOnHuggingFaceSpaces - whether the app is running on a HuggingFace spaces, needs to be checked server-side
|
||||
*/
|
||||
export function useHuggingFaceRedirect(runningOnHuggingFaceSpaces: boolean) {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const isInIframe = () => {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
runningOnHuggingFaceSpaces &&
|
||||
typeof window !== "undefined" &&
|
||||
isInIframe()
|
||||
) {
|
||||
void router.push("/auth/hf-spaces");
|
||||
}
|
||||
}, [router, runningOnHuggingFaceSpaces]);
|
||||
}
|
||||
|
||||
const signInErrors = [
|
||||
{
|
||||
code: "OAuthAccountNotLinked",
|
||||
@@ -239,8 +303,13 @@ const signInErrors = [
|
||||
},
|
||||
];
|
||||
|
||||
export default function SignIn({ authProviders, signUpDisabled }: PageProps) {
|
||||
export default function SignIn({
|
||||
authProviders,
|
||||
signUpDisabled,
|
||||
runningOnHuggingFaceSpaces,
|
||||
}: PageProps) {
|
||||
const router = useRouter();
|
||||
useHuggingFaceRedirect(runningOnHuggingFaceSpaces);
|
||||
|
||||
// handle NextAuth error codes: https://next-auth.js.org/configuration/pages#sign-in-page
|
||||
const nextAuthError =
|
||||
|
||||
@@ -20,7 +20,11 @@ import { useState } from "react";
|
||||
import { LangfuseIcon } from "@/src/components/LangfuseLogo";
|
||||
import { CloudPrivacyNotice } from "@/src/features/auth/components/AuthCloudPrivacyNotice";
|
||||
import { CloudRegionSwitch } from "@/src/features/auth/components/AuthCloudRegionSwitch";
|
||||
import { SSOButtons, type PageProps } from "@/src/pages/auth/sign-in";
|
||||
import {
|
||||
SSOButtons,
|
||||
useHuggingFaceRedirect,
|
||||
type PageProps,
|
||||
} from "@/src/pages/auth/sign-in";
|
||||
import { PasswordInput } from "@/src/components/ui/password-input";
|
||||
import { Divider } from "@tremor/react";
|
||||
import { Turnstile } from "@marsidev/react-turnstile";
|
||||
@@ -28,7 +32,12 @@ import { Turnstile } from "@marsidev/react-turnstile";
|
||||
// Use the same getServerSideProps function as src/pages/auth/sign-in.tsx
|
||||
export { getServerSideProps } from "@/src/pages/auth/sign-in";
|
||||
|
||||
export default function SignIn({ authProviders }: PageProps) {
|
||||
export default function SignIn({
|
||||
authProviders,
|
||||
runningOnHuggingFaceSpaces,
|
||||
}: PageProps) {
|
||||
useHuggingFaceRedirect(runningOnHuggingFaceSpaces);
|
||||
|
||||
const [turnstileToken, setTurnstileToken] = useState<string>();
|
||||
// Used to refresh turnstile as the token can only be used once
|
||||
const [turnstileCData, setTurnstileCData] = useState<string>(
|
||||
|
||||
+106
-2
@@ -11,7 +11,6 @@ import { verifyPassword } from "@/src/features/auth-credentials/lib/credentialsS
|
||||
import { parseFlags } from "@/src/features/feature-flags/utils";
|
||||
import { env } from "@/src/env.mjs";
|
||||
import { createProjectMembershipsOnSignup } from "@/src/features/auth/lib/createProjectMembershipsOnSignup";
|
||||
import { type Adapter } from "next-auth/adapters";
|
||||
|
||||
// Providers
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
@@ -23,6 +22,7 @@ import EmailProvider from "next-auth/providers/email";
|
||||
import Auth0Provider from "next-auth/providers/auth0";
|
||||
import CognitoProvider from "next-auth/providers/cognito";
|
||||
import AzureADProvider from "next-auth/providers/azure-ad";
|
||||
import KeycloakProvider from "next-auth/providers/keycloak";
|
||||
import { type Provider } from "next-auth/providers/index";
|
||||
import { getCookieName, getCookieOptions } from "./utils/cookies";
|
||||
import {
|
||||
@@ -33,6 +33,7 @@ import { z } from "zod";
|
||||
import { CloudConfigSchema } from "@langfuse/shared";
|
||||
import {
|
||||
CustomSSOProvider,
|
||||
GitHubEnterpriseProvider,
|
||||
traceException,
|
||||
sendResetPasswordVerificationRequest,
|
||||
instrumentAsync,
|
||||
@@ -40,6 +41,11 @@ import {
|
||||
} from "@langfuse/shared/src/server";
|
||||
import { getOrganizationPlan } from "@/src/features/entitlements/server/getOrganizationPlan";
|
||||
import { projectRoleAccessRights } from "@/src/features/rbac/constants/projectAccessRights";
|
||||
import {
|
||||
type AdapterUser,
|
||||
type Adapter,
|
||||
type AdapterAccount,
|
||||
} from "next-auth/adapters";
|
||||
|
||||
function canCreateOrganizations(userEmail: string | null): boolean {
|
||||
// if no allowlist is set or no active EE key, allow all users to create organizations
|
||||
@@ -169,11 +175,16 @@ if (
|
||||
clientId: env.AUTH_CUSTOM_CLIENT_ID,
|
||||
clientSecret: env.AUTH_CUSTOM_CLIENT_SECRET,
|
||||
issuer: env.AUTH_CUSTOM_ISSUER,
|
||||
idToken: env.AUTH_CUSTOM_ID_TOKEN !== "false", // defaults to true
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_CUSTOM_ALLOW_ACCOUNT_LINKING === "true",
|
||||
authorization: {
|
||||
params: { scope: env.AUTH_CUSTOM_SCOPE ?? "openid email profile" },
|
||||
},
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_CUSTOM_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_CUSTOM_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -184,6 +195,10 @@ if (env.AUTH_GOOGLE_CLIENT_ID && env.AUTH_GOOGLE_CLIENT_SECRET)
|
||||
clientSecret: env.AUTH_GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_GOOGLE_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_GOOGLE_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_GOOGLE_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -199,6 +214,10 @@ if (
|
||||
issuer: env.AUTH_OKTA_ISSUER,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_OKTA_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_OKTA_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_OKTA_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -214,6 +233,10 @@ if (
|
||||
issuer: env.AUTH_AUTH0_ISSUER,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_AUTH0_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_AUTH0_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_AUTH0_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -224,9 +247,34 @@ if (env.AUTH_GITHUB_CLIENT_ID && env.AUTH_GITHUB_CLIENT_SECRET)
|
||||
clientSecret: env.AUTH_GITHUB_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_GITHUB_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_GITHUB_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_GITHUB_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
env.AUTH_GITHUB_ENTERPRISE_CLIENT_ID &&
|
||||
env.AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET &&
|
||||
env.AUTH_GITHUB_ENTERPRISE_BASE_URL
|
||||
) {
|
||||
staticProviders.push(
|
||||
GitHubEnterpriseProvider({
|
||||
clientId: env.AUTH_GITHUB_ENTERPRISE_CLIENT_ID,
|
||||
clientSecret: env.AUTH_GITHUB_ENTERPRISE_CLIENT_SECRET,
|
||||
enterprise: { baseUrl: env.AUTH_GITHUB_ENTERPRISE_BASE_URL },
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_GITHUB_ENTERPRISE_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method:
|
||||
env.AUTH_GITHUB_ENTERPRISE_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_GITHUB_ENTERPRISE_CHECKS,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (env.AUTH_GITLAB_CLIENT_ID && env.AUTH_GITLAB_CLIENT_SECRET)
|
||||
staticProviders.push(
|
||||
GitLabProvider({
|
||||
@@ -235,6 +283,10 @@ if (env.AUTH_GITLAB_CLIENT_ID && env.AUTH_GITLAB_CLIENT_SECRET)
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_GITLAB_ALLOW_ACCOUNT_LINKING === "true",
|
||||
issuer: env.AUTH_GITLAB_ISSUER,
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_GITLAB_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_GITLAB_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -250,6 +302,10 @@ if (
|
||||
tenantId: env.AUTH_AZURE_AD_TENANT_ID,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_AZURE_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_AZURE_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_AZURE_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -263,16 +319,40 @@ if (
|
||||
clientId: env.AUTH_COGNITO_CLIENT_ID,
|
||||
clientSecret: env.AUTH_COGNITO_CLIENT_SECRET,
|
||||
issuer: env.AUTH_COGNITO_ISSUER,
|
||||
checks: env.AUTH_COGNITO_CHECKS ?? "nonce",
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_COGNITO_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_COGNITO_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
env.AUTH_KEYCLOAK_CLIENT_ID &&
|
||||
env.AUTH_KEYCLOAK_CLIENT_SECRET &&
|
||||
env.AUTH_KEYCLOAK_ISSUER
|
||||
)
|
||||
staticProviders.push(
|
||||
KeycloakProvider({
|
||||
clientId: env.AUTH_KEYCLOAK_CLIENT_ID,
|
||||
clientSecret: env.AUTH_KEYCLOAK_CLIENT_SECRET,
|
||||
issuer: env.AUTH_KEYCLOAK_ISSUER,
|
||||
allowDangerousEmailAccountLinking:
|
||||
env.AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING === "true",
|
||||
client: {
|
||||
token_endpoint_auth_method: env.AUTH_KEYCLOAK_CLIENT_AUTH_METHOD,
|
||||
},
|
||||
checks: env.AUTH_KEYCLOAK_CHECKS,
|
||||
}),
|
||||
);
|
||||
|
||||
// Extend Prisma Adapter
|
||||
const prismaAdapter = PrismaAdapter(prisma);
|
||||
const ignoredAccountFields = env.AUTH_IGNORE_ACCOUNT_FIELDS?.split(",") ?? [];
|
||||
const extendedPrismaAdapter: Adapter = {
|
||||
...prismaAdapter,
|
||||
async createUser(profile) {
|
||||
async createUser(profile: Omit<AdapterUser, "id">) {
|
||||
if (!prismaAdapter.createUser)
|
||||
throw new Error("createUser not implemented");
|
||||
if (
|
||||
@@ -294,6 +374,30 @@ const extendedPrismaAdapter: Adapter = {
|
||||
|
||||
return user;
|
||||
},
|
||||
|
||||
async linkAccount(data: AdapterAccount) {
|
||||
if (!prismaAdapter.linkAccount)
|
||||
throw new Error("NextAuth: prismaAdapter.linkAccount not implemented");
|
||||
|
||||
// Keycloak returns incompatible data with the nextjs-auth schema
|
||||
// (refresh_expires_in and not-before-policy in).
|
||||
// So, we need to remove this data from the payload before linking an account.
|
||||
// https://github.com/nextauthjs/next-auth/issues/7655
|
||||
if (data.provider === "keycloak") {
|
||||
delete data["refresh_expires_in"];
|
||||
delete data["not-before-policy"];
|
||||
}
|
||||
|
||||
// Optionally, remove fields returned by the provider that cause issues with the adapter
|
||||
// Configure via AUTH_IGNORE_ACCOUNT_FIELDS
|
||||
for (const ignoredField of ignoredAccountFields) {
|
||||
if (ignoredField in data) {
|
||||
delete data[ignoredField];
|
||||
}
|
||||
}
|
||||
|
||||
await prismaAdapter.linkAccount(data);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,11 @@ if [ -z "$DATABASE_URL" ]; then
|
||||
echo "Error: Required database environment variables are not set. Provide a postgres url for DATABASE_URL."
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$DATABASE_ARGS" ]; then
|
||||
# Append ARGS to DATABASE_URL
|
||||
DATABASE_URL="${DATABASE_URL}?$DATABASE_ARGS"
|
||||
export DATABASE_URL
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run the command passed to the docker image on start
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "worker",
|
||||
"version": "2.92.0",
|
||||
"version": "2.95.5",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@@ -82,7 +82,7 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jsonpath-plus": "10.0.7"
|
||||
"jsonpath-plus": "10.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v2.92.0";
|
||||
export const VERSION = "v2.95.5";
|
||||
|
||||
Reference in New Issue
Block a user