move web to use shared env package

This commit is contained in:
bkellam 2025-11-02 15:24:19 -08:00
parent 174497d369
commit 5b65264034
57 changed files with 164 additions and 214 deletions

View file

@ -84,7 +84,7 @@ SOURCEBOT_TELEMETRY_DISABLED=true # Disables telemetry collection
# NEXT_PUBLIC_SOURCEBOT_VERSION=
# CONFIG_MAX_REPOS_NO_TOKEN=
# NODE_ENV=
NODE_ENV=development
# SOURCEBOT_TENANCY_MODE=single
# NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT=

View file

@ -32,7 +32,6 @@
"@sourcebot/db": "workspace:*",
"@sourcebot/schemas": "workspace:*",
"@sourcebot/shared": "workspace:*",
"@t3-oss/env-core": "^0.12.0",
"@types/express": "^5.0.0",
"argparse": "^2.0.1",
"azure-devops-node-api": "^15.1.1",
@ -52,6 +51,6 @@
"posthog-node": "^4.2.1",
"prom-client": "^15.1.3",
"simple-git": "^3.27.0",
"zod": "^3.24.3"
"zod": "^3.25.74"
}
}

View file

@ -1,6 +1,6 @@
import * as Sentry from "@sentry/node";
import { createLogger } from "@sourcebot/shared";
import { env } from "@sourcebot/shared";
import { env } from "@sourcebot/shared/client";
const logger = createLogger('instrument');

View file

@ -1,12 +1,13 @@
import { env as clientEnv } from "@sourcebot/shared/client";
import { env } from "@sourcebot/shared";
import { PostHog } from 'posthog-node';
import { PosthogEvent, PosthogEventMap } from './posthogEvents.js';
let posthog: PostHog | undefined = undefined;
if (env.NEXT_PUBLIC_POSTHOG_PAPIK) {
if (clientEnv.NEXT_PUBLIC_POSTHOG_PAPIK) {
posthog = new PostHog(
env.NEXT_PUBLIC_POSTHOG_PAPIK,
clientEnv.NEXT_PUBLIC_POSTHOG_PAPIK,
{
host: "https://us.i.posthog.com",
}
@ -23,7 +24,7 @@ export function captureEvent<E extends PosthogEvent>(event: E, properties: Posth
event: event,
properties: {
...properties,
sourcebot_version: env.NEXT_PUBLIC_SOURCEBOT_VERSION,
sourcebot_version: clientEnv.NEXT_PUBLIC_SOURCEBOT_VERSION,
},
});
}

View file

@ -20,7 +20,7 @@
"strip-json-comments": "^5.0.1",
"triple-beam": "^1.4.1",
"winston": "^3.15.0",
"zod": "^3.24.3"
"zod": "^3.25.74"
},
"devDependencies": {
"@types/micromatch": "^4.0.9",

View file

@ -1,6 +1,6 @@
import crypto from 'crypto';
import fs from 'fs';
import { env } from './env.js';
import { env } from './env.server.js';
import { Token } from '@sourcebot/schemas/v3/shared.type';
import { SecretManagerServiceClient } from "@google-cloud/secret-manager";

View file

@ -1,7 +1,8 @@
import { base64Decode } from "./utils.js";
import { z } from "zod";
import { createLogger } from "./logger.js";
import { env } from "./env.js";
import { env } from "./env.server.js";
import { env as clientEnv } from "./env.client.js";
import { SOURCEBOT_SUPPORT_EMAIL, SOURCEBOT_UNLIMITED_SEATS } from "./constants.js";
import { verifySignature } from "./crypto.js";
@ -89,8 +90,8 @@ export const getLicenseKey = (): LicenseKeyPayload | null => {
}
export const getPlan = (): Plan => {
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT) {
if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo") {
if (clientEnv.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT) {
if (clientEnv.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === "demo") {
return "cloud:demo";
}

View file

@ -0,0 +1,27 @@
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";
import { SOURCEBOT_CLOUD_ENVIRONMENT } from "./constants.js";
export const env = createEnv({
clientPrefix: "NEXT_PUBLIC_",
client: {
NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: z.enum(SOURCEBOT_CLOUD_ENVIRONMENT).optional(),
NEXT_PUBLIC_SOURCEBOT_VERSION: z.string().default("unknown"),
NEXT_PUBLIC_POSTHOG_PAPIK: z.string().optional(),
NEXT_PUBLIC_SENTRY_BACKEND_DSN: z.string().optional(),
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().optional(),
NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY: z.string().optional(),
NEXT_PUBLIC_LANGFUSE_BASE_URL: z.string().optional()
},
runtimeEnvStrict: {
NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: process.env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT,
NEXT_PUBLIC_SOURCEBOT_VERSION: process.env.NEXT_PUBLIC_SOURCEBOT_VERSION,
NEXT_PUBLIC_POSTHOG_PAPIK: process.env.NEXT_PUBLIC_POSTHOG_PAPIK,
NEXT_PUBLIC_SENTRY_BACKEND_DSN: process.env.NEXT_PUBLIC_SENTRY_BACKEND_DSN,
NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY: process.env.NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY,
NEXT_PUBLIC_LANGFUSE_BASE_URL: process.env.NEXT_PUBLIC_LANGFUSE_BASE_URL,
},
emptyStringAsUndefined: true,
skipValidation: process.env.SKIP_ENV_VALIDATION === "1",
});

View file

@ -1,16 +1,62 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";
import { SOURCEBOT_CLOUD_ENVIRONMENT } from "@sourcebot/shared/client";
import { SourcebotConfig } from "@sourcebot/schemas/v3/index.type";
import { getTokenFromConfig } from "./crypto.js";
import { loadConfig } from "./utils.js";
import { tenancyModeSchema } from "./types.js";
// Booleans are specified as 'true' or 'false' strings.
const booleanSchema = z.enum(["true", "false"]);
export const tenancyModeSchema = z.enum(["multi", "single"]);
// Numbers are treated as strings in .env files.
// coerce helps us convert them to numbers.
// @see: https://zod.dev/?id=coercion-for-primitives
const numberSchema = z.coerce.number();
const resolveEnvironmentVariableOverridesFromConfig = async (config: SourcebotConfig): Promise<Record<string, string>> => {
if (!config.environmentOverrides) {
return {};
}
const resolved: Record<string, string> = {};
console.debug('resolving environment variable overrides');
for (const [key, override] of Object.entries(config.environmentOverrides)) {
switch (override.type) {
case 'token':
resolved[key] = await getTokenFromConfig(override.value);
break;
case 'boolean':
resolved[key] = override.value ? 'true' : 'false';
break;
case 'number':
resolved[key] = override.value.toString();
break;
case 'string':
resolved[key] = override.value;
break;
}
}
return resolved;
}
// Merge process.env with environment variables resolved from config.json
const runtimeEnv = await (async () => {
const configPath = process.env.CONFIG_PATH;
if (!configPath) {
return process.env;
}
const config = await loadConfig(configPath);
const overrides = await resolveEnvironmentVariableOverridesFromConfig(config);
return {
...process.env,
...overrides,
}
})();
export const env = createEnv({
server: {
// Zoekt
@ -18,7 +64,6 @@ export const env = createEnv({
// Auth
FORCE_ENABLE_ANONYMOUS_ACCESS: booleanSchema.default('false'),
AUTH_SECRET: z.string(),
AUTH_URL: z.string().url(),
AUTH_CREDENTIALS_LOGIN_ENABLED: booleanSchema.default('true'),
@ -75,7 +120,7 @@ export const env = createEnv({
DATABASE_URL: z.string().url(),
SOURCEBOT_TENANCY_MODE: tenancyModeSchema.default("single"),
CONFIG_PATH: z.string().optional(),
CONFIG_PATH: z.string(),
// Misc UI flags
SECURITY_CARD_ENABLED: booleanSchema.default('false'),
@ -137,31 +182,30 @@ export const env = createEnv({
// @NOTE: Take care to update actions.ts when changing the name of this.
EXPERIMENT_SELF_SERVE_REPO_INDEXING_GITHUB_TOKEN: z.string().optional(),
EXPERIMENT_EE_PERMISSION_SYNC_ENABLED: booleanSchema.default('false'),
},
// @NOTE: Please make sure of the following:
// - Make sure you destructure all client variables in
// the `experimental__runtimeEnv` block below.
// - Update the Dockerfile to pass these variables as build-args.
client: {
// PostHog
NEXT_PUBLIC_POSTHOG_PAPIK: z.string().optional(),
// Misc
NEXT_PUBLIC_SOURCEBOT_VERSION: z.string().default('unknown'),
SOURCEBOT_ENCRYPTION_KEY: z.string(),
SOURCEBOT_INSTALL_ID: z.string().default("unknown"),
NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: z.enum(SOURCEBOT_CLOUD_ENVIRONMENT).optional(),
FALLBACK_GITHUB_CLOUD_TOKEN: z.string().optional(),
FALLBACK_GITLAB_CLOUD_TOKEN: z.string().optional(),
FALLBACK_GITEA_CLOUD_TOKEN: z.string().optional(),
NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY: z.string().optional(),
NEXT_PUBLIC_LANGFUSE_BASE_URL: z.string().optional()
REDIS_URL: z.string().url().default("redis://localhost:6379"),
REDIS_REMOVE_ON_COMPLETE: numberSchema.default(0),
REDIS_REMOVE_ON_FAIL: numberSchema.default(100),
DEBUG_ENABLE_GROUPMQ_LOGGING: booleanSchema.default('false'),
CONNECTION_MANAGER_UPSERT_TIMEOUT_MS: numberSchema.default(300000),
REPO_SYNC_RETRY_BASE_SLEEP_SECONDS: numberSchema.default(60),
GITLAB_CLIENT_QUERY_TIMEOUT_SECONDS: numberSchema.default(60 * 10),
SOURCEBOT_LOG_LEVEL: z.enum(["info", "debug", "warn", "error"]).default("info"),
SOURCEBOT_STRUCTURED_LOGGING_ENABLED: booleanSchema.default("false"),
SOURCEBOT_STRUCTURED_LOGGING_FILE: z.string().optional(),
},
// For Next.js >= 13.4.4, you only need to destructure client variables:
experimental__runtimeEnv: {
NEXT_PUBLIC_POSTHOG_PAPIK: process.env.NEXT_PUBLIC_POSTHOG_PAPIK,
NEXT_PUBLIC_SOURCEBOT_VERSION: process.env.NEXT_PUBLIC_SOURCEBOT_VERSION,
NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: process.env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT,
NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY: process.env.NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY,
NEXT_PUBLIC_LANGFUSE_BASE_URL: process.env.NEXT_PUBLIC_LANGFUSE_BASE_URL,
},
skipValidation: process.env.SKIP_ENV_VALIDATION === "1",
runtimeEnv,
emptyStringAsUndefined: true,
skipValidation: process.env.SKIP_ENV_VALIDATION === "1",
});

View file

@ -1,110 +0,0 @@
import { createEnv } from "@t3-oss/env-core";
import { z } from "zod";
import { SOURCEBOT_CLOUD_ENVIRONMENT } from "./constants.js";
import { SourcebotConfig } from "@sourcebot/schemas/v3/index.type";
import { getTokenFromConfig } from "./crypto.js";
import { loadConfig } from "./utils.js";
// Booleans are specified as 'true' or 'false' strings.
const booleanSchema = z.enum(["true", "false"]);
// Numbers are treated as strings in .env files.
// coerce helps us convert them to numbers.
// @see: https://zod.dev/?id=coercion-for-primitives
const numberSchema = z.coerce.number();
const resolveEnvironmentVariableOverridesFromConfig = async (config: SourcebotConfig): Promise<Record<string, string>> => {
if (!config.environmentOverrides) {
return {};
}
const resolved: Record<string, string> = {};
console.debug('resolving environment variable overrides');
for (const [key, override] of Object.entries(config.environmentOverrides)) {
switch (override.type) {
case 'token':
resolved[key] = await getTokenFromConfig(override.value);
break;
case 'boolean':
resolved[key] = override.value ? 'true' : 'false';
break;
case 'number':
resolved[key] = override.value.toString();
break;
case 'string':
resolved[key] = override.value;
break;
}
}
return resolved;
}
// Merge process.env with environment variables resolved from config.json
const runtimeEnv = await (async () => {
const configPath = process.env.CONFIG_PATH;
if (!configPath) {
return process.env;
}
const config = await loadConfig(configPath);
const overrides = await resolveEnvironmentVariableOverridesFromConfig(config);
return {
...process.env,
...overrides,
}
})();
export const env = createEnv({
server: {
SOURCEBOT_EE_LICENSE_KEY: z.string().optional(),
SOURCEBOT_PUBLIC_KEY_PATH: z.string(),
SOURCEBOT_ENCRYPTION_KEY: z.string(),
SOURCEBOT_TELEMETRY_DISABLED: booleanSchema.default("false"),
SOURCEBOT_INSTALL_ID: z.string().default("unknown"),
DATA_CACHE_DIR: z.string(),
FALLBACK_GITHUB_CLOUD_TOKEN: z.string().optional(),
FALLBACK_GITLAB_CLOUD_TOKEN: z.string().optional(),
FALLBACK_GITEA_CLOUD_TOKEN: z.string().optional(),
REDIS_URL: z.string().url().default("redis://localhost:6379"),
REDIS_REMOVE_ON_COMPLETE: numberSchema.default(0),
REDIS_REMOVE_ON_FAIL: numberSchema.default(100),
DEBUG_ENABLE_GROUPMQ_LOGGING: booleanSchema.default('false'),
DATABASE_URL: z.string().url().default("postgresql://postgres:postgres@localhost:5432/postgres"),
CONFIG_PATH: z.string(),
CONNECTION_MANAGER_UPSERT_TIMEOUT_MS: numberSchema.default(300000),
REPO_SYNC_RETRY_BASE_SLEEP_SECONDS: numberSchema.default(60),
GITLAB_CLIENT_QUERY_TIMEOUT_SECONDS: numberSchema.default(60 * 10),
EXPERIMENT_EE_PERMISSION_SYNC_ENABLED: booleanSchema.default('false'),
AUTH_EE_GITHUB_BASE_URL: z.string().optional(),
AUTH_EE_GITLAB_BASE_URL: z.string().default("https://gitlab.com"),
SOURCEBOT_LOG_LEVEL: z.enum(["info", "debug", "warn", "error"]).default("info"),
SOURCEBOT_STRUCTURED_LOGGING_ENABLED: booleanSchema.default("false"),
SOURCEBOT_STRUCTURED_LOGGING_FILE: z.string().optional(),
LOGTAIL_TOKEN: z.string().optional(),
LOGTAIL_HOST: z.string().url().optional(),
},
client: {
NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT: z.enum(SOURCEBOT_CLOUD_ENVIRONMENT).optional(),
NEXT_PUBLIC_SOURCEBOT_VERSION: z.string().default("unknown"),
NEXT_PUBLIC_POSTHOG_PAPIK: z.string().optional(),
NEXT_PUBLIC_SENTRY_BACKEND_DSN: z.string().optional(),
NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().optional(),
},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnv,
emptyStringAsUndefined: true,
skipValidation: process.env.SKIP_ENV_VALIDATION === "1",
});

View file

@ -1,2 +1,4 @@
export * from "./constants.js";
export * from "./constants.js";
export {
env
} from "./env.client.js";

View file

@ -16,6 +16,7 @@ export type {
export {
repoMetadataSchema,
repoIndexingJobMetadataSchema,
tenancyModeSchema,
} from "./types.js";
export {
base64Decode,
@ -27,7 +28,7 @@ export {
export * from "./constants.js";
export {
env
} from "./env.js";
} from "./env.server.js";
export {
createLogger,
} from "./logger.js";

View file

@ -2,7 +2,7 @@ import winston, { format, Logger } from 'winston';
import { Logtail } from '@logtail/node';
import { LogtailTransport } from '@logtail/winston';
import { MESSAGE } from 'triple-beam';
import { env } from './env.js';
import { env } from './env.server.js';
/**
* Logger configuration with support for structured JSON logging.

View file

@ -43,3 +43,5 @@ export const repoIndexingJobMetadataSchema = z.object({
});
export type RepoIndexingJobMetadata = z.infer<typeof repoIndexingJobMetadataSchema>;
export const tenancyModeSchema = z.enum(["multi", "single"]);

View file

@ -1,4 +1,3 @@
await import("./src/env.mjs");
import { withSentryConfig } from "@sentry/nextjs";
@ -8,7 +7,7 @@ const nextConfig = {
// This is required when using standalone builds.
// @see: https://env.t3.gg/docs/nextjs#create-your-schema
transpilePackages: ["@t3-oss/env-nextjs", "@t3-oss/env-core"],
transpilePackages: ["@t3-oss/env-core"],
// @see : https://posthog.com/docs/advanced/proxy/nextjs
async rewrites() {

View file

@ -96,7 +96,6 @@
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
"@stripe/react-stripe-js": "^3.1.1",
"@stripe/stripe-js": "^5.6.0",
"@t3-oss/env-nextjs": "^0.12.0",
"@tailwindcss/typography": "^0.5.16",
"@tanstack/react-query": "^5.53.3",
"@tanstack/react-table": "^8.20.5",

View file

@ -1,7 +1,7 @@
'use server';
import { getAuditService } from "@/ee/features/audit/factory";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { addUserToOrganization, orgHasAvailability } from "@/lib/authUtils";
import { ErrorCode } from "@/lib/errorCodes";
import { notAuthenticated, notFound, orgNotFound, ServiceError, ServiceErrorException, unexpectedError } from "@/lib/serviceError";

View file

@ -1,7 +1,7 @@
import Link from "next/link";
import { NavigationMenu } from "../components/navigationMenu";
import { FaCogs } from "react-icons/fa";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
const agents = [
{

View file

@ -9,7 +9,7 @@ import { RepositoryCarousel } from "../components/repositoryCarousel";
import { NavigationMenu } from "../components/navigationMenu";
import { Separator } from "@/components/ui/separator";
import { DemoCards } from "./components/demoCards";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { loadJsonFile } from "@sourcebot/shared";
import { DemoExamples, demoExamplesSchema } from "@/types";

View file

@ -6,7 +6,7 @@ import { NavigationMenu as NavigationMenuBase } from "@/components/ui/navigation
import { Separator } from "@/components/ui/separator";
import { getSubscriptionInfo } from "@/ee/features/billing/actions";
import { IS_BILLING_ENABLED } from "@/ee/features/billing/stripe";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { ServiceErrorException } from "@/lib/serviceError";
import { isServiceError } from "@/lib/utils";
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";

View file

@ -32,7 +32,7 @@ import { useKeymapType } from "@/hooks/useKeymapType"
import { useSession } from "next-auth/react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { signOut } from "next-auth/react"
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
import posthog from "posthog-js";
import { useDomain } from "@/hooks/useDomain";

View file

@ -16,7 +16,7 @@ import { getSubscriptionInfo } from "@/ee/features/billing/actions";
import { PendingApprovalCard } from "./components/pendingApproval";
import { SubmitJoinRequest } from "./components/submitJoinRequest";
import { hasEntitlement } from "@sourcebot/shared";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { GcpIapAuth } from "./components/gcpIapAuth";
import { getAnonymousAccessStatus, getMemberApprovalRequired } from "@/actions";
import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard";

View file

@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
import { env } from "@/env.mjs"
import { env } from "@sourcebot/shared"
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
import { ServiceErrorException } from "@/lib/serviceError"
import { cn, getCodeHostInfoForRepo, isServiceError } from "@/lib/utils"

View file

@ -4,7 +4,7 @@ import { DisplayDate } from "@/app/[domain]/components/DisplayDate";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants";
import { notFound, ServiceErrorException } from "@/lib/serviceError";
import { isServiceError } from "@/lib/utils";

View file

@ -10,8 +10,8 @@ import { getConnectionStats, getMe, getOrgAccountRequests } from "@/actions";
import { ServiceErrorException } from "@/lib/serviceError";
import { getOrgFromDomain } from "@/data/org";
import { OrgRole } from "@prisma/client";
import { env } from "@/env.mjs";
import { hasEntitlement } from "@sourcebot/shared";
import { env } from "@sourcebot/shared/client";
interface LayoutProps {
children: React.ReactNode;

View file

@ -4,7 +4,7 @@ import { Info, Mail } from "lucide-react";
import { getOrgMembers } from "@/actions";
import { isServiceError } from "@/lib/utils";
import { notFound, ServiceErrorException } from "@/lib/serviceError";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
interface LicensePageProps {
params: Promise<{

View file

@ -8,7 +8,7 @@ import { isServiceError } from "@/lib/utils";
import Link from "next/link";
import { ArrowLeftIcon } from "@radix-ui/react-icons";
import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { IS_BILLING_ENABLED } from "@/ee/features/billing/stripe";
import { getSubscriptionInfo } from "@/ee/features/billing/actions";

View file

@ -6,7 +6,7 @@ import { isServiceError } from "@/lib/utils";
import { serviceErrorResponse } from "@/lib/serviceError";
import { StatusCodes } from "http-status-codes";
import { ErrorCode } from "@/lib/errorCodes";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { getEntitlements } from "@sourcebot/shared";
export const GET = async (request: NextRequest) => {

View file

@ -4,7 +4,7 @@ import Stripe from 'stripe';
import { prisma } from '@/prisma';
import { StripeSubscriptionStatus } from '@sourcebot/db';
import { stripeClient } from '@/ee/features/billing/stripe';
import { env } from '@/env.mjs';
import { env } from '@sourcebot/shared';
import { createLogger } from "@sourcebot/shared";
const logger = createLogger('stripe-webhook');

View file

@ -1,4 +1,4 @@
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
import { GetVersionResponse } from "@/lib/types";
// Note: In Next.JS 14, GET methods with no params are cached by default at build time.

View file

@ -4,7 +4,7 @@ import { NextRequest } from "next/server";
import { App, Octokit } from "octokit";
import { WebhookEventDefinition} from "@octokit/webhooks/types";
import { EndpointDefaults } from "@octokit/types";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { processGitHubPullRequest } from "@/features/agents/review-agent/app";
import { throttling } from "@octokit/plugin-throttling";
import fs from "fs";

View file

@ -1,7 +1,7 @@
'use client';
import React, { useState, useEffect } from "react";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
interface AuthSecurityNoticeProps {
closable?: boolean;

View file

@ -6,7 +6,7 @@ import { getOrgMetadata } from "@/lib/utils"
import { headers } from "next/headers"
import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"
import { hasEntitlement } from "@sourcebot/shared"
import { env } from "@/env.mjs"
import { env } from "@sourcebot/shared"
export async function OrganizationAccessSettings() {
const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN);

View file

@ -6,7 +6,7 @@ import { PostHogProvider } from "./posthogProvider";
import { Toaster } from "@/components/ui/toaster";
import { TooltipProvider } from "@/components/ui/tooltip";
import { SessionProvider } from "next-auth/react";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { PlanProvider } from "@/features/entitlements/planProvider";
import { getEntitlements } from "@sourcebot/shared";

View file

@ -17,7 +17,7 @@ import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch";
import { redirect } from "next/navigation";
import { BetweenHorizontalStart, Brain, GitBranchIcon, LockIcon } from "lucide-react";
import { hasEntitlement } from "@sourcebot/shared";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { GcpIapAuth } from "@/app/[domain]/components/gcpIapAuth";
interface OnboardingProps {

View file

@ -4,7 +4,7 @@ import { usePostHog } from 'posthog-js/react'
import { PostHogProvider as PHProvider } from 'posthog-js/react'
import { usePathname, useSearchParams } from "next/navigation"
import { Suspense, useEffect } from "react"
import { env } from '@/env.mjs'
import { env } from '@sourcebot/shared/client'
import { useSession } from 'next-auth/react'
import { captureEvent } from '@/hooks/useCaptureEvent'

View file

@ -4,7 +4,7 @@ import Credentials from "next-auth/providers/credentials"
import EmailProvider from "next-auth/providers/nodemailer";
import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/prisma";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { User } from '@sourcebot/db';
import 'next-auth/jwt';
import type { Provider } from "next-auth/providers";

View file

@ -2,7 +2,7 @@ import { IAuditService } from '@/ee/features/audit/types';
import { MockAuditService } from '@/ee/features/audit/mockAuditService';
import { AuditService } from '@/ee/features/audit/auditService';
import { hasEntitlement } from '@sourcebot/shared';
import { env } from '@/env.mjs';
import { env } from '@sourcebot/shared';
let enterpriseService: IAuditService | undefined;

View file

@ -7,7 +7,7 @@ import { prisma } from "@/prisma";
import { OrgRole } from "@sourcebot/db";
import { stripeClient } from "./stripe";
import { isServiceError } from "@/lib/utils";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { StatusCodes } from "http-status-codes";
import { ErrorCode } from "@/lib/errorCodes";
import { headers } from "next/headers";

View file

@ -1,5 +1,5 @@
import 'server-only';
import { env } from '@/env.mjs'
import { env } from '@sourcebot/shared'
import Stripe from "stripe";
import { hasEntitlement } from '@sourcebot/shared';

View file

@ -1,4 +1,4 @@
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
import Okta from "next-auth/providers/okta";

View file

@ -2,7 +2,7 @@ import { Octokit } from "octokit";
import { generatePrReviews } from "@/features/agents/review-agent/nodes/generatePrReview";
import { githubPushPrReviews } from "@/features/agents/review-agent/nodes/githubPushPrReviews";
import { githubPrParser } from "@/features/agents/review-agent/nodes/githubPrParser";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { GitHubPullRequest } from "@/features/agents/review-agent/types";
import path from "path";
import fs from "fs";

View file

@ -1,6 +1,6 @@
import OpenAI from "openai";
import { sourcebot_file_diff_review, sourcebot_file_diff_review_schema } from "@/features/agents/review-agent/types";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import fs from "fs";
import { createLogger } from "@sourcebot/shared";

View file

@ -1,7 +1,7 @@
'use server';
import { sew, withAuth, withOrgMembership } from "@/actions";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { SOURCEBOT_GUEST_USER_ID } from "@/lib/constants";
import { ErrorCode } from "@/lib/errorCodes";
import { chatIsReadonly, notFound, ServiceError, serviceErrorResponse } from "@/lib/serviceError";

View file

@ -1,4 +1,5 @@
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { env as clientEnv } from "@sourcebot/shared/client";
import { getFileSource } from "@/features/search/fileSourceApi";
import { isServiceError } from "@/lib/utils";
import { ProviderOptions } from "@ai-sdk/provider-utils";
@ -140,7 +141,7 @@ export const createAgentStream = async ({
},
// Only enable langfuse traces in cloud environments.
experimental_telemetry: {
isEnabled: env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined,
isEnabled: clientEnv.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT !== undefined,
metadata: {
langfuseTraceId: traceId,
},

View file

@ -17,7 +17,7 @@ import { isServiceError } from "@/lib/utils";
import { useDomain } from "@/hooks/useDomain";
import useCaptureEvent from "@/hooks/useCaptureEvent";
import { LangfuseWeb } from "langfuse";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
interface AnswerCardProps {
answerText: string;

View file

@ -4,7 +4,7 @@ import { FILE_REFERENCE_REGEX, ANSWER_TAG } from './constants';
import { SBChatMessage, SBChatMessagePart } from './types';
// Mock the env module
vi.mock('@/env.mjs', () => ({
vi.mock('@sourcebot/shared', () => ({
env: {
SOURCEBOT_CHAT_FILE_MAX_CHARACTERS: 4000,
}

View file

@ -1,7 +1,7 @@
'use server';
import { sew } from '@/actions';
import { env } from '@/env.mjs';
import { env } from '@sourcebot/shared';
import { notFound, unexpectedError } from '@/lib/serviceError';
import { withOptionalAuthV2 } from '@/withAuthV2';
import { Repo } from '@sourcebot/db';

View file

@ -1,4 +1,4 @@
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
interface ZoektRequest {
path: string,

View file

@ -3,7 +3,7 @@
import { CaptureOptions } from "posthog-js";
import posthog from "posthog-js";
import { PosthogEvent, PosthogEventMap } from "../lib/posthogEvents";
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared/client";
export function captureEvent<E extends PosthogEvent>(event: E, properties: PosthogEventMap[E], options?: CaptureOptions) {
if(!options) {

View file

@ -2,10 +2,8 @@ import { createGuestUser } from '@/lib/authUtils';
import { SOURCEBOT_SUPPORT_EMAIL } from "@/lib/constants";
import { prisma } from "@/prisma";
import { OrgRole } from '@sourcebot/db';
import { createLogger } from "@sourcebot/shared";
import { hasEntitlement, loadConfig } from '@sourcebot/shared';
import { createLogger, env, hasEntitlement, loadConfig } from "@sourcebot/shared";
import { getOrgFromDomain } from './data/org';
import { env } from './env.mjs';
import { SINGLE_TENANT_ORG_DOMAIN, SINGLE_TENANT_ORG_ID, SOURCEBOT_GUEST_USER_ID } from './lib/constants';
import { ServiceErrorException } from './lib/serviceError';
import { getOrgMetadata, isServiceError } from './lib/utils';

View file

@ -1,6 +1,6 @@
import { z } from "zod";
import { getReposResponseSchema, getVersionResponseSchema, repositoryQuerySchema, searchContextQuerySchema } from "./schemas";
import { tenancyModeSchema } from "@/env.mjs";
import { tenancyModeSchema } from "@sourcebot/shared";
export type KeymapType = "default" | "vim";

View file

@ -1,15 +1,10 @@
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { env } from './env.mjs'
import { SINGLE_TENANT_ORG_DOMAIN } from '@/lib/constants'
export async function middleware(request: NextRequest) {
const url = request.nextUrl.clone();
if (env.SOURCEBOT_TENANCY_MODE !== 'single') {
return NextResponse.next();
}
if (
url.pathname.startsWith('/login') ||
url.pathname.startsWith('/redeem') ||

View file

@ -1,5 +1,5 @@
import 'server-only';
import { env } from "@/env.mjs";
import { env } from "@sourcebot/shared";
import { Prisma, PrismaClient } from "@sourcebot/db";
import { hasEntitlement } from "@sourcebot/shared";

View file

@ -18,18 +18,10 @@ vi.mock('./auth', () => ({
auth: mocks.auth,
}));
vi.mock('@/env.mjs', () => ({
env: {}
}));
vi.mock('next/headers', () => ({
headers: mocks.headers,
}));
vi.mock('@/env.mjs', () => ({
env: {}
}));
vi.mock('@/prisma', async () => {
// @see: https://github.com/prisma/prisma/discussions/20244#discussioncomment-7976447
const actual = await vi.importActual<typeof import('@/__mocks__/prisma')>('@/__mocks__/prisma');
@ -45,6 +37,7 @@ vi.mock('server-only', () => ({
vi.mock('@sourcebot/shared', () => ({
hasEntitlement: mocks.hasEntitlement,
hashSecret: vi.fn((secret: string) => secret),
env: {}
}));
// Test utility to set the mock session

View file

@ -35,8 +35,7 @@
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"src/env.mjs"
".next/types/**/*.ts"
],
"exclude": [
"node_modules"

View file

@ -7896,7 +7896,6 @@ __metadata:
"@sourcebot/db": "workspace:*"
"@sourcebot/schemas": "workspace:*"
"@sourcebot/shared": "workspace:*"
"@t3-oss/env-core": "npm:^0.12.0"
"@types/argparse": "npm:^2.0.16"
"@types/express": "npm:^5.0.0"
"@types/micromatch": "npm:^4.0.9"
@ -7925,7 +7924,7 @@ __metadata:
tsx: "npm:^4.19.1"
typescript: "npm:^5.6.2"
vitest: "npm:^2.1.9"
zod: "npm:^3.24.3"
zod: "npm:^3.25.74"
languageName: unknown
linkType: soft
@ -8009,7 +8008,7 @@ __metadata:
tsc-watch: "npm:6.2.1"
typescript: "npm:^5.7.3"
winston: "npm:^3.15.0"
zod: "npm:^3.24.3"
zod: "npm:^3.25.74"
languageName: unknown
linkType: soft