diff --git a/.dockerignore b/.dockerignore
index aad8fbb16c3..6b5bbfdcab9 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -3,7 +3,7 @@ Dockerfile
**/node_modules
npm-debug.log
README.md
-.next
+**/.next
.git
.github
.turbo
diff --git a/apps/builder/.env.local.example b/.env.dev.example
similarity index 85%
rename from apps/builder/.env.local.example
rename to .env.dev.example
index d86bc0dd558..cb029f9bcfa 100644
--- a/apps/builder/.env.local.example
+++ b/.env.dev.example
@@ -1,6 +1,8 @@
-DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
# Make sure to change this to your own random string of 32 characters (https://docs.typebot.io/self-hosting/docker#2-add-the-required-configuration)
ENCRYPTION_SECRET=H+KbL/OFrqbEuDy/1zX8bsPG+spXri3S
+
+DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
+
NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_VIEWER_URL=http://localhost:3001
@@ -14,5 +16,4 @@ S3_PORT=9000
S3_ENDPOINT=localhost
S3_SSL=false
-# For more configuration options check out:
-# https://docs.typebot.io/self-hosting/configuration
\ No newline at end of file
+# For more configuration options check out: https://docs.typebot.io/self-hosting/configuration
\ No newline at end of file
diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000000..2fdb4c724ed
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,10 @@
+# Make sure to change this to your own random string of 32 characters (https://docs.typebot.io/self-hosting/docker#2-add-the-required-configuration)
+ENCRYPTION_SECRET=do+UspMmB/rewbX2K/rskFmtgGSSZ8Ta
+
+DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
+
+NEXTAUTH_URL=
+NEXT_PUBLIC_VIEWER_URL=
+
+ADMIN_EMAIL=
+# For more configuration options check out: https://docs.typebot.io/self-hosting/configuration
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ed076309e11..0236cd30b5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
node_modules
.next
-.env
.env.local
workspace.code-workspace
.DS_Store
@@ -34,4 +33,6 @@ __env.js
typebotsToFix.json
**/scripts/logs
-snapshots
\ No newline at end of file
+snapshots
+
+.env
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3e299dc81f4..d42d77d183f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,11 +36,7 @@ These apps are built with awesome web technologies including [Typescript](https:
2. Set up environment variables
- Copy [`apps/builder/.env.local.example`](apps/builder/.env.local.example) to `apps/builder/.env.local`
-
- Copy [`apps/viewer/.env.local.example`](apps/viewer/.env.local.example) to `apps/viewer/.env.local`
-
- Copy [`packages/prisma/.env.example` ](packages/prisma/.env.example)to `packages/prisma/.env`
+ Copy [`.env.dev.example`](./.env.dev.example) to `.env`
Check out the [Configuration guide](https://docs.typebot.io/self-hosting/configuration) if you want to enable more options
diff --git a/Dockerfile b/Dockerfile
index 86108905949..20e313f8ff8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,7 +21,8 @@ RUN pnpm install
COPY --from=pruner /app/out/full/ .
COPY turbo.json turbo.json
-RUN pnpm turbo run build:docker --filter=${SCOPE}...
+ENV ENCRYPTION_SECRET=encryption_secret_placeholder123 DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot NEXTAUTH_URL=http://localhost:3000 NEXT_PUBLIC_VIEWER_URL=http://localhost:3001
+RUN pnpm turbo run build --filter=${SCOPE}...
FROM base AS runner
WORKDIR /app
@@ -32,16 +33,15 @@ RUN apt-get -qy update \
&& apt-get autoremove -yq \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
-COPY ./packages/prisma ./packages/prisma
-COPY ./apps/${SCOPE}/.env.docker ./apps/${SCOPE}/.env.production
-COPY --from=builder /app/node_modules ./node_modules
+COPY ./packages/prisma/postgresql ./packages/prisma/postgresql
COPY --from=builder /app/apps/${SCOPE}/public ./apps/${SCOPE}/public
COPY --from=builder --chown=node:node /app/apps/${SCOPE}/.next/standalone ./
COPY --from=builder --chown=node:node /app/apps/${SCOPE}/.next/static ./apps/${SCOPE}/.next/static
+RUN pnpm install next-runtime-env prisma
+RUN pnpm prisma generate --schema=packages/prisma/postgresql/schema.prisma;
-COPY scripts/inject-runtime-env.sh scripts/${SCOPE}-entrypoint.sh ./
-RUN chmod +x ./${SCOPE}-entrypoint.sh \
- && chmod +x ./inject-runtime-env.sh
+COPY scripts/${SCOPE}-entrypoint.sh ./
+RUN chmod +x ./${SCOPE}-entrypoint.sh
ENTRYPOINT ./${SCOPE}-entrypoint.sh
EXPOSE 3000
diff --git a/README.md b/README.md
index 0dd094be7eb..06d8c98671d 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Typebot is an open-source chatbot builder. It allows you to create advanced chat
-
+
diff --git a/apps/builder/.env.docker b/apps/builder/.env.docker
deleted file mode 100644
index fd9e2c3906c..00000000000
--- a/apps/builder/.env.docker
+++ /dev/null
@@ -1,13 +0,0 @@
-# Don't edit this file
-NEXT_PUBLIC_VIEWER_URL=
-NEXT_PUBLIC_SMTP_FROM=
-NEXT_PUBLIC_GOOGLE_API_KEY=
-NEXT_PUBLIC_GIPHY_API_KEY=
-NEXT_PUBLIC_STRIPE_PUBLIC_KEY=
-NEXT_PUBLIC_SENTRY_DSN=
-NEXT_PUBLIC_VIEWER_INTERNAL_URL=
-NEXT_PUBLIC_E2E_TEST=
-NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME=
-NEXT_PUBLIC_UNSPLASH_APP_NAME=
-NEXT_PUBLIC_UNSPLASH_ACCESS_KEY=
-NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID=
diff --git a/apps/builder/.eslintignore b/apps/builder/.eslintignore
deleted file mode 100644
index 4b831b41542..00000000000
--- a/apps/builder/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-next.config.js
\ No newline at end of file
diff --git a/apps/builder/next.config.js b/apps/builder/next.config.mjs
similarity index 64%
rename from apps/builder/next.config.js
rename to apps/builder/next.config.mjs
index 230f3b10174..a71cd725cad 100644
--- a/apps/builder/next.config.js
+++ b/apps/builder/next.config.mjs
@@ -1,6 +1,14 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-const { withSentryConfig } = require('@sentry/nextjs')
-const path = require('path')
+import { withSentryConfig } from '@sentry/nextjs'
+import { join, dirname } from 'path'
+import '@typebot.io/env/dist/env.mjs'
+import { configureRuntimeEnv } from 'next-runtime-env/build/configure.js'
+import { fileURLToPath } from 'url'
+
+const __filename = fileURLToPath(import.meta.url)
+
+const __dirname = dirname(__filename)
+
+configureRuntimeEnv()
/** @type {import('next').NextConfig} */
const nextConfig = {
@@ -10,13 +18,14 @@ const nextConfig = {
'@typebot.io/lib',
'@typebot.io/schemas',
'@typebot.io/emails',
+ '@typebot.io/env',
],
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'pt', 'de'],
},
experimental: {
- outputFileTracingRoot: path.join(__dirname, '../../'),
+ outputFileTracingRoot: join(__dirname, '../../'),
},
headers: async () => {
return [
@@ -38,7 +47,7 @@ const sentryWebpackPluginOptions = {
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder',
}
-module.exports = process.env.NEXT_PUBLIC_SENTRY_DSN
+export default process.env.NEXT_PUBLIC_SENTRY_DSN
? withSentryConfig(
{
...nextConfig,
diff --git a/apps/builder/package.json b/apps/builder/package.json
index e0e3205bb6a..6de7bc022e2 100644
--- a/apps/builder/package.json
+++ b/apps/builder/package.json
@@ -3,13 +3,11 @@
"version": "0.1.0",
"license": "AGPL-3.0-or-later",
"scripts": {
- "dev": "cross-env ENVSH_ENV=.env.local bash ../../scripts/inject-runtime-env.sh next dev -p 3000",
- "build": "cross-env ENVSH_ENV=.env.local bash ../../scripts/inject-runtime-env.sh next build",
- "build:docker": "next build",
- "build:env": "cd ../.. && cross-env ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash scripts/inject-runtime-env.sh",
- "start": "next start",
- "lint": "next lint",
- "test": "pnpm playwright test",
+ "dev": "dotenv -e ./.env -e ../../.env -- next dev -p 3000",
+ "build": "dotenv -e ./.env -e ../../.env -- next build",
+ "start": "dotenv -e ./.env -e ../../.env -- next start",
+ "lint": "dotenv -e ./.env -e ../../.env -- next lint",
+ "test": "dotenv -e ./.env -e ../../.env -- pnpm playwright test",
"test:show-report": "pnpm playwright show-report src/test/reporters"
},
"dependencies": {
@@ -30,6 +28,7 @@
"@paralleldrive/cuid2": "2.2.1",
"@sentry/nextjs": "7.58.1",
"@stripe/stripe-js": "1.54.1",
+ "@t3-oss/env-nextjs": "^0.6.0",
"@tanstack/react-query": "^4.29.19",
"@tanstack/react-table": "8.9.3",
"@trpc/client": "10.34.0",
@@ -37,6 +36,7 @@
"@trpc/react-query": "10.34.0",
"@trpc/server": "10.34.0",
"@typebot.io/emails": "workspace:*",
+ "@typebot.io/env": "workspace:*",
"@typebot.io/nextjs": "workspace:*",
"@udecode/plate-basic-marks": "21.1.5",
"@udecode/plate-common": "^21.1.5",
@@ -81,6 +81,7 @@
"qs": "6.11.2",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "sharp": "^0.32.4",
"slate": "0.94.1",
"slate-history": "0.93.0",
"slate-hyperscript": "0.77.0",
@@ -112,7 +113,8 @@
"@types/qs": "6.9.7",
"@types/react": "18.2.15",
"@types/tinycolor2": "1.4.3",
- "dotenv": "16.3.1",
+ "dotenv-cli": "^7.2.1",
+ "next-runtime-env": "^1.6.2",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
"superjson": "^1.12.4",
diff --git a/apps/builder/sentry.client.config.js b/apps/builder/sentry.client.config.js
index 8c0c540e06b..fad585c2a4f 100644
--- a/apps/builder/sentry.client.config.js
+++ b/apps/builder/sentry.client.config.js
@@ -1,9 +1,7 @@
import * as Sentry from '@sentry/nextjs'
-const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
-
Sentry.init({
- dsn: SENTRY_DSN,
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
ignoreErrors: [
'ResizeObserver loop limit exceeded',
'ResizeObserver loop completed with undelivered notifications.',
diff --git a/apps/builder/sentry.server.config.js b/apps/builder/sentry.server.config.js
index c7e31494cf6..05de5446c0d 100644
--- a/apps/builder/sentry.server.config.js
+++ b/apps/builder/sentry.server.config.js
@@ -1,8 +1,6 @@
import * as Sentry from '@sentry/nextjs'
-const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
-
Sentry.init({
- dsn: SENTRY_DSN,
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-builder',
})
diff --git a/apps/builder/src/components/ImageUploadContent/GiphyPicker.tsx b/apps/builder/src/components/ImageUploadContent/GiphyPicker.tsx
index 8ed9043af59..afdcf79fab4 100644
--- a/apps/builder/src/components/ImageUploadContent/GiphyPicker.tsx
+++ b/apps/builder/src/components/ImageUploadContent/GiphyPicker.tsx
@@ -3,14 +3,14 @@ import { GiphyFetch } from '@giphy/js-fetch-api'
import { Grid } from '@giphy/react-components'
import { GiphyLogo } from '../logos/GiphyLogo'
import React, { useState } from 'react'
-import { env, isEmpty } from '@typebot.io/lib'
import { TextInput } from '../inputs'
+import { env } from '@typebot.io/env'
type GiphySearchFormProps = {
onSubmit: (url: string) => void
}
-const giphyFetch = new GiphyFetch(env('GIPHY_API_KEY') as string)
+const giphyFetch = new GiphyFetch(env.NEXT_PUBLIC_GIPHY_API_KEY ?? '')
export const GiphyPicker = ({ onSubmit }: GiphySearchFormProps) => {
const [inputValue, setInputValue] = useState('')
@@ -21,7 +21,7 @@ export const GiphyPicker = ({ onSubmit }: GiphySearchFormProps) => {
const fetchGifsTrending = (offset: number) =>
giphyFetch.trending({ offset, limit: 10 })
- return isEmpty(env('GIPHY_API_KEY')) ? (
+ return !env.NEXT_PUBLIC_GIPHY_API_KEY ? (
NEXT_PUBLIC_GIPHY_API_KEY is missing in environment
) : (
diff --git a/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx b/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx
index e4c3b724710..5721769205f 100644
--- a/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx
+++ b/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx
@@ -14,16 +14,17 @@ import {
Text,
useColorModeValue,
} from '@chakra-ui/react'
-import { env, isDefined, isEmpty } from '@typebot.io/lib'
+import { isDefined } from '@typebot.io/lib'
import { useCallback, useEffect, useRef, useState } from 'react'
import { createApi } from 'unsplash-js'
import { Basic as UnsplashImage } from 'unsplash-js/dist/methods/photos/types'
import { TextInput } from '../inputs'
import { UnsplashLogo } from '../logos/UnsplashLogo'
import { TextLink } from '../TextLink'
+import { env } from '@typebot.io/env'
const api = createApi({
- accessKey: env('UNSPLASH_ACCESS_KEY') ?? '',
+ accessKey: env.NEXT_PUBLIC_UNSPLASH_ACCESS_KEY ?? '',
})
type Props = {
@@ -124,7 +125,7 @@ export const UnsplashPicker = ({ imageSize, onImageSelect }: Props) => {
searchRandomImages()
}, [])
- if (isEmpty(env('UNSPLASH_ACCESS_KEY')))
+ if (!env.NEXT_PUBLIC_UNSPLASH_ACCESS_KEY)
return (
NEXT_PUBLIC_UNSPLASH_ACCESS_KEY is missing in environment
)
@@ -143,9 +144,7 @@ export const UnsplashPicker = ({ imageSize, onImageSelect }: Props) => {
/>
@@ -224,9 +223,7 @@ const UnsplashImage = ({ image, onClick }: UnsplashImageProps) => {
diff --git a/apps/builder/src/components/inputs/AutocompleteInput.tsx b/apps/builder/src/components/inputs/AutocompleteInput.tsx
index 45eb5014dbd..228350a64d5 100644
--- a/apps/builder/src/components/inputs/AutocompleteInput.tsx
+++ b/apps/builder/src/components/inputs/AutocompleteInput.tsx
@@ -13,7 +13,7 @@ import {
} from '@chakra-ui/react'
import { useState, useRef, useEffect, ReactNode } from 'react'
import { useDebouncedCallback } from 'use-debounce'
-import { env, isDefined } from '@typebot.io/lib'
+import { isDefined } from '@typebot.io/lib'
import { useOutsideClick } from '@/hooks/useOutsideClick'
import { useParentModal } from '@/features/graph/providers/ParentModalProvider'
import { VariablesButton } from '@/features/variables/components/VariablesButton'
@@ -21,6 +21,7 @@ import { Variable } from '@typebot.io/schemas'
import { injectVariableInText } from '@/features/variables/helpers/injectVariableInTextInput'
import { focusInput } from '@/helpers/focusInput'
import { MoreInfoTooltip } from '../MoreInfoTooltip'
+import { env } from '@typebot.io/env'
type Props = {
items: string[]
@@ -57,7 +58,7 @@ export const AutocompleteInput = ({
const onChange = useDebouncedCallback(
_onChange,
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
useEffect(() => {
diff --git a/apps/builder/src/components/inputs/CodeEditor.tsx b/apps/builder/src/components/inputs/CodeEditor.tsx
index 8a8480d7d24..a569d07030b 100644
--- a/apps/builder/src/components/inputs/CodeEditor.tsx
+++ b/apps/builder/src/components/inputs/CodeEditor.tsx
@@ -9,7 +9,7 @@ import { useEffect, useRef, useState } from 'react'
import { useDebouncedCallback } from 'use-debounce'
import { VariablesButton } from '@/features/variables/components/VariablesButton'
import { Variable } from '@typebot.io/schemas'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import CodeMirror, { ReactCodeMirrorRef } from '@uiw/react-codemirror'
import { tokyoNight } from '@uiw/codemirror-theme-tokyo-night'
import { githubLight } from '@uiw/codemirror-theme-github'
@@ -53,7 +53,7 @@ export const CodeEditor = ({
_setValue(value)
onChange && onChange(value)
},
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
const handleVariableSelected = (variable?: Pick) => {
diff --git a/apps/builder/src/components/inputs/NumberInput.tsx b/apps/builder/src/components/inputs/NumberInput.tsx
index 54270ad904a..ac4730da0ab 100644
--- a/apps/builder/src/components/inputs/NumberInput.tsx
+++ b/apps/builder/src/components/inputs/NumberInput.tsx
@@ -14,7 +14,7 @@ import {
import { Variable, VariableString } from '@typebot.io/schemas'
import { useEffect, useState } from 'react'
import { useDebouncedCallback } from 'use-debounce'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import { MoreInfoTooltip } from '../MoreInfoTooltip'
type Value = HasVariable extends true | undefined
@@ -47,7 +47,7 @@ export const NumberInput = ({
const onValueChangeDebounced = useDebouncedCallback(
onValueChange,
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
useEffect(
diff --git a/apps/builder/src/components/inputs/TextInput.tsx b/apps/builder/src/components/inputs/TextInput.tsx
index ecfbd1a8775..1d5f32b32dc 100644
--- a/apps/builder/src/components/inputs/TextInput.tsx
+++ b/apps/builder/src/components/inputs/TextInput.tsx
@@ -19,7 +19,7 @@ import React, {
useState,
} from 'react'
import { useDebouncedCallback } from 'use-debounce'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import { MoreInfoTooltip } from '../MoreInfoTooltip'
export type TextInputProps = {
@@ -69,7 +69,7 @@ export const TextInput = forwardRef(function TextInput(
const onChange = useDebouncedCallback(
// eslint-disable-next-line @typescript-eslint/no-empty-function
_onChange ?? (() => {}),
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
useEffect(() => {
diff --git a/apps/builder/src/components/inputs/Textarea.tsx b/apps/builder/src/components/inputs/Textarea.tsx
index 9948f8a4c62..59f620b9ad3 100644
--- a/apps/builder/src/components/inputs/Textarea.tsx
+++ b/apps/builder/src/components/inputs/Textarea.tsx
@@ -11,7 +11,7 @@ import {
import { Variable } from '@typebot.io/schemas'
import React, { useEffect, useRef, useState } from 'react'
import { useDebouncedCallback } from 'use-debounce'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import { MoreInfoTooltip } from '../MoreInfoTooltip'
type Props = {
@@ -46,7 +46,7 @@ export const Textarea = ({
)
const onChange = useDebouncedCallback(
_onChange,
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
useEffect(() => {
diff --git a/apps/builder/src/features/account/UserProvider.tsx b/apps/builder/src/features/account/UserProvider.tsx
index 60f9d822dd6..5ec0113236b 100644
--- a/apps/builder/src/features/account/UserProvider.tsx
+++ b/apps/builder/src/features/account/UserProvider.tsx
@@ -1,12 +1,13 @@
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/router'
import { createContext, ReactNode, useEffect, useState } from 'react'
-import { env, isDefined, isNotDefined } from '@typebot.io/lib'
+import { isDefined, isNotDefined } from '@typebot.io/lib'
import { User } from '@typebot.io/prisma'
import { setUser as setSentryUser } from '@sentry/nextjs'
import { useToast } from '@/hooks/useToast'
import { updateUserQuery } from './queries/updateUserQuery'
import { useDebouncedCallback } from 'use-debounce'
+import { env } from '@typebot.io/env'
export const userContext = createContext<{
user?: User
@@ -66,7 +67,7 @@ export const UserProvider = ({ children }: { children: ReactNode }) => {
if (error) showToast({ title: error.name, description: error.message })
await refreshUser()
},
- env('E2E_TEST') === 'true' ? 0 : debounceTimeout
+ env.NEXT_PUBLIC_E2E_TEST ? 0 : debounceTimeout
)
useEffect(() => {
diff --git a/apps/builder/src/features/account/account.spec.ts b/apps/builder/src/features/account/account.spec.ts
index ffed13c177a..588e81e0fd9 100644
--- a/apps/builder/src/features/account/account.spec.ts
+++ b/apps/builder/src/features/account/account.spec.ts
@@ -1,5 +1,6 @@
import { getTestAsset } from '@/test/utils/playwright'
import test, { expect } from '@playwright/test'
+import { env } from '@typebot.io/env'
import { userId } from '@typebot.io/lib/playwright/databaseSetup'
test.describe.configure({ mode: 'parallel' })
@@ -15,9 +16,9 @@ test('should display user info properly', async ({ page }) => {
await expect(page.locator('img >> nth=1')).toHaveAttribute(
'src',
new RegExp(
- `${process.env.S3_ENDPOINT}${
- process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''
- }/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
+ `${env.S3_ENDPOINT}${env.S3_PORT ? `:${env.S3_PORT}` : ''}/${
+ env.S3_BUCKET
+ }/public/users/${userId}/avatar`,
'gm'
)
)
diff --git a/apps/builder/src/features/account/hooks/useApiTokens.ts b/apps/builder/src/features/account/hooks/useApiTokens.ts
index c45d8f6c051..d38aafd373a 100644
--- a/apps/builder/src/features/account/hooks/useApiTokens.ts
+++ b/apps/builder/src/features/account/hooks/useApiTokens.ts
@@ -1,6 +1,6 @@
import { fetcher } from '@/helpers/fetcher'
import useSWR from 'swr'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import { ApiTokenFromServer } from '../types'
type ServerResponse = {
@@ -18,7 +18,7 @@ export const useApiTokens = ({
userId ? `/api/users/${userId}/api-tokens` : null,
fetcher,
{
- dedupingInterval: env('E2E_TEST') === 'true' ? 0 : undefined,
+ dedupingInterval: env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined,
}
)
if (error) onError(error)
diff --git a/apps/builder/src/features/auth/api/customAdapter.ts b/apps/builder/src/features/auth/api/customAdapter.ts
index 1a1265e87e4..828ea8f373c 100644
--- a/apps/builder/src/features/auth/api/customAdapter.ts
+++ b/apps/builder/src/features/auth/api/customAdapter.ts
@@ -14,6 +14,7 @@ import { convertInvitationsToCollaborations } from '@/features/auth/helpers/conv
import { getNewUserInvitations } from '@/features/auth/helpers/getNewUserInvitations'
import { joinWorkspaces } from '@/features/auth/helpers/joinWorkspaces'
import { parseWorkspaceDefaultPlan } from '@/features/workspace/helpers/parseWorkspaceDefaultPlan'
+import { env } from '@typebot.io/env'
export function customAdapter(p: PrismaClient): Adapter {
return {
@@ -26,8 +27,8 @@ export function customAdapter(p: PrismaClient): Adapter {
user.email
)
if (
- process.env.DISABLE_SIGNUP === 'true' &&
- process.env.ADMIN_EMAIL !== user.email &&
+ env.DISABLE_SIGNUP &&
+ env.ADMIN_EMAIL !== user.email &&
invitations.length === 0 &&
workspaceInvitations.length === 0
)
diff --git a/apps/builder/src/features/auth/components/OnboardingPage.tsx b/apps/builder/src/features/auth/components/OnboardingPage.tsx
index 6640d6c55ab..1f0a02c090a 100644
--- a/apps/builder/src/features/auth/components/OnboardingPage.tsx
+++ b/apps/builder/src/features/auth/components/OnboardingPage.tsx
@@ -13,8 +13,8 @@ import { useRouter } from 'next/router'
import { useEffect, useRef, useState } from 'react'
import confetti from 'canvas-confetti'
import { useUser } from '@/features/account/hooks/useUser'
-import { env, isEmpty } from '@typebot.io/lib'
import { useI18n } from '@/locales'
+import { env } from '@typebot.io/env'
const totalSteps = 5
@@ -37,7 +37,7 @@ export const OnboardingPage = () => {
useEffect(() => {
if (!user?.createdAt) return
- if (isNewUser === false || isEmpty(env('ONBOARDING_TYPEBOT_ID')))
+ if (isNewUser === false || !env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID)
replace('/typebots')
}, [isNewUser, replace, user?.createdAt])
@@ -90,7 +90,7 @@ export const OnboardingPage = () => {
{
diff --git a/apps/builder/src/features/auth/helpers/getAuthenticatedUser.ts b/apps/builder/src/features/auth/helpers/getAuthenticatedUser.ts
index 269fc0e896f..99e48c70433 100644
--- a/apps/builder/src/features/auth/helpers/getAuthenticatedUser.ts
+++ b/apps/builder/src/features/auth/helpers/getAuthenticatedUser.ts
@@ -5,7 +5,7 @@ import { User } from '@typebot.io/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getServerSession } from 'next-auth'
import { mockedUser } from '../mockedUser'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
export const getAuthenticatedUser = async (
req: NextApiRequest,
@@ -13,12 +13,11 @@ export const getAuthenticatedUser = async (
): Promise => {
const bearerToken = extractBearerToken(req)
if (bearerToken) return authenticateByToken(bearerToken)
- const user =
- env('E2E_TEST') === 'true'
- ? mockedUser
- : ((await getServerSession(req, res, authOptions))?.user as
- | User
- | undefined)
+ const user = env.NEXT_PUBLIC_E2E_TEST
+ ? mockedUser
+ : ((await getServerSession(req, res, authOptions))?.user as
+ | User
+ | undefined)
if (!user || !('id' in user)) return
setUser({ id: user.id })
return user
diff --git a/apps/builder/src/features/billing/api/createCheckoutSession.ts b/apps/builder/src/features/billing/api/createCheckoutSession.ts
index ce5a21eb35d..de94a44aa70 100644
--- a/apps/builder/src/features/billing/api/createCheckoutSession.ts
+++ b/apps/builder/src/features/billing/api/createCheckoutSession.ts
@@ -6,6 +6,7 @@ import Stripe from 'stripe'
import { z } from 'zod'
import { parseSubscriptionItems } from '../helpers/parseSubscriptionItems'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
+import { env } from '@typebot.io/env'
export const createCheckoutSession = authenticatedProcedure
.meta({
@@ -57,7 +58,7 @@ export const createCheckoutSession = authenticatedProcedure
},
ctx: { user },
}) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
@@ -82,14 +83,13 @@ export const createCheckoutSession = authenticatedProcedure
code: 'NOT_FOUND',
message: 'Workspace not found',
})
-
if (workspace.stripeId)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Customer already exists, use updateSubscription endpoint.',
})
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
diff --git a/apps/builder/src/features/billing/api/createCustomCheckoutSession.ts b/apps/builder/src/features/billing/api/createCustomCheckoutSession.ts
index 89d042b6f8b..44987097749 100644
--- a/apps/builder/src/features/billing/api/createCustomCheckoutSession.ts
+++ b/apps/builder/src/features/billing/api/createCustomCheckoutSession.ts
@@ -5,6 +5,7 @@ import { Plan } from '@typebot.io/prisma'
import Stripe from 'stripe'
import { z } from 'zod'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
+import { env } from '@typebot.io/env'
export const createCustomCheckoutSession = authenticatedProcedure
.meta({
@@ -31,7 +32,7 @@ export const createCustomCheckoutSession = authenticatedProcedure
)
.mutation(
async ({ input: { email, workspaceId, returnUrl }, ctx: { user } }) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
@@ -61,7 +62,7 @@ export const createCustomCheckoutSession = authenticatedProcedure
code: 'NOT_FOUND',
message: 'Custom plan not found',
})
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
diff --git a/apps/builder/src/features/billing/api/getBillingPortalUrl.ts b/apps/builder/src/features/billing/api/getBillingPortalUrl.ts
index 16f08ef6688..b79b7a4d572 100644
--- a/apps/builder/src/features/billing/api/getBillingPortalUrl.ts
+++ b/apps/builder/src/features/billing/api/getBillingPortalUrl.ts
@@ -4,6 +4,7 @@ import { TRPCError } from '@trpc/server'
import Stripe from 'stripe'
import { z } from 'zod'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
+import { env } from '@typebot.io/env'
export const getBillingPortalUrl = authenticatedProcedure
.meta({
@@ -26,7 +27,7 @@ export const getBillingPortalUrl = authenticatedProcedure
})
)
.query(async ({ input: { workspaceId }, ctx: { user } }) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'STRIPE_SECRET_KEY var is missing',
@@ -50,12 +51,12 @@ export const getBillingPortalUrl = authenticatedProcedure
code: 'NOT_FOUND',
message: 'Workspace not found',
})
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
const portalSession = await stripe.billingPortal.sessions.create({
customer: workspace.stripeId,
- return_url: `${process.env.NEXTAUTH_URL}/typebots`,
+ return_url: `${env.NEXTAUTH_URL}/typebots`,
})
return {
billingPortalUrl: portalSession.url,
diff --git a/apps/builder/src/features/billing/api/getSubscription.ts b/apps/builder/src/features/billing/api/getSubscription.ts
index 0760937bc02..84e1864d013 100644
--- a/apps/builder/src/features/billing/api/getSubscription.ts
+++ b/apps/builder/src/features/billing/api/getSubscription.ts
@@ -4,8 +4,9 @@ import { TRPCError } from '@trpc/server'
import Stripe from 'stripe'
import { z } from 'zod'
import { subscriptionSchema } from '@typebot.io/schemas/features/billing/subscription'
-import { priceIds } from '@typebot.io/lib/pricing'
import { isReadWorkspaceFobidden } from '@/features/workspace/helpers/isReadWorkspaceFobidden'
+import { priceIds } from '@typebot.io/lib/api/pricing'
+import { env } from '@typebot.io/env'
export const getSubscription = authenticatedProcedure
.meta({
@@ -28,7 +29,7 @@ export const getSubscription = authenticatedProcedure
})
)
.query(async ({ input: { workspaceId }, ctx: { user } }) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
@@ -55,7 +56,7 @@ export const getSubscription = authenticatedProcedure
return {
subscription: null,
}
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
const subscriptions = await stripe.subscriptions.list({
diff --git a/apps/builder/src/features/billing/api/listInvoices.ts b/apps/builder/src/features/billing/api/listInvoices.ts
index 33ec979c363..8e9ac082bd6 100644
--- a/apps/builder/src/features/billing/api/listInvoices.ts
+++ b/apps/builder/src/features/billing/api/listInvoices.ts
@@ -6,6 +6,7 @@ import { isDefined } from '@typebot.io/lib'
import { z } from 'zod'
import { invoiceSchema } from '@typebot.io/schemas/features/billing/invoice'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
+import { env } from '@typebot.io/env'
export const listInvoices = authenticatedProcedure
.meta({
@@ -28,7 +29,7 @@ export const listInvoices = authenticatedProcedure
})
)
.query(async ({ input: { workspaceId }, ctx: { user } }) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'STRIPE_SECRET_KEY var is missing',
@@ -52,7 +53,7 @@ export const listInvoices = authenticatedProcedure
code: 'NOT_FOUND',
message: 'Workspace not found',
})
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
const invoices = await stripe.invoices.list({
diff --git a/apps/builder/src/features/billing/api/updateSubscription.ts b/apps/builder/src/features/billing/api/updateSubscription.ts
index 5996305468c..3f8dc575a8d 100644
--- a/apps/builder/src/features/billing/api/updateSubscription.ts
+++ b/apps/builder/src/features/billing/api/updateSubscription.ts
@@ -7,15 +7,13 @@ import { workspaceSchema } from '@typebot.io/schemas'
import Stripe from 'stripe'
import { isDefined } from '@typebot.io/lib'
import { z } from 'zod'
-import {
- getChatsLimit,
- getStorageLimit,
- priceIds,
-} from '@typebot.io/lib/pricing'
+import { getChatsLimit, getStorageLimit } from '@typebot.io/lib/pricing'
import { chatPriceIds, storagePriceIds } from './getSubscription'
import { createCheckoutSessionUrl } from './createCheckoutSession'
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
import { getUsage } from '@typebot.io/lib/api/getUsage'
+import { env } from '@typebot.io/env'
+import { priceIds } from '@typebot.io/lib/api/pricing'
export const updateSubscription = authenticatedProcedure
.meta({
@@ -57,7 +55,7 @@ export const updateSubscription = authenticatedProcedure
},
ctx: { user },
}) => {
- if (!process.env.STRIPE_SECRET_KEY)
+ if (!env.STRIPE_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Stripe environment variables are missing',
@@ -85,7 +83,7 @@ export const updateSubscription = authenticatedProcedure
code: 'NOT_FOUND',
message: 'Workspace not found',
})
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+ const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
const { data } = await stripe.subscriptions.list({
@@ -95,10 +93,9 @@ export const updateSubscription = authenticatedProcedure
})
const subscription = data[0] as Stripe.Subscription | undefined
const currentPlanItemId = subscription?.items.data.find((item) =>
- [
- process.env.STRIPE_STARTER_PRODUCT_ID,
- process.env.STRIPE_PRO_PRODUCT_ID,
- ].includes(item.price.product.toString())
+ [env.STRIPE_STARTER_PRODUCT_ID, env.STRIPE_PRO_PRODUCT_ID].includes(
+ item.price.product.toString()
+ )
)?.id
const currentAdditionalChatsItemId = subscription?.items.data.find(
(item) => chatPriceIds.includes(item.price.id)
diff --git a/apps/builder/src/features/billing/billing.spec.ts b/apps/builder/src/features/billing/billing.spec.ts
index 7dbd5a6f49b..107ef01f975 100644
--- a/apps/builder/src/features/billing/billing.spec.ts
+++ b/apps/builder/src/features/billing/billing.spec.ts
@@ -12,6 +12,7 @@ import {
deleteWorkspaces,
injectFakeResults,
} from '@typebot.io/lib/playwright/databaseActions'
+import { env } from '@typebot.io/env'
const usageWorkspaceId = createId()
const usageTypebotId = createId()
@@ -147,7 +148,7 @@ test('plan changes should work', async ({ page }) => {
planChangeWorkspaceId,
[
{
- price: process.env.STRIPE_STARTER_MONTHLY_PRICE_ID,
+ price: env.STRIPE_STARTER_MONTHLY_PRICE_ID,
quantity: 1,
},
],
diff --git a/apps/builder/src/features/billing/helpers/parseSubscriptionItems.ts b/apps/builder/src/features/billing/helpers/parseSubscriptionItems.ts
index 6ef05ab1e85..ba8911c9e88 100644
--- a/apps/builder/src/features/billing/helpers/parseSubscriptionItems.ts
+++ b/apps/builder/src/features/billing/helpers/parseSubscriptionItems.ts
@@ -1,8 +1,5 @@
-import {
- getChatsLimit,
- getStorageLimit,
- priceIds,
-} from '@typebot.io/lib/pricing'
+import { getChatsLimit, getStorageLimit } from '@typebot.io/lib/pricing'
+import { priceIds } from '@typebot.io/lib/api/pricing'
export const parseSubscriptionItems = (
plan: 'STARTER' | 'PRO',
diff --git a/apps/builder/src/features/blocks/inputs/payment/payment.spec.ts b/apps/builder/src/features/blocks/inputs/payment/payment.spec.ts
index c02141356df..9000cd86d79 100644
--- a/apps/builder/src/features/blocks/inputs/payment/payment.spec.ts
+++ b/apps/builder/src/features/blocks/inputs/payment/payment.spec.ts
@@ -4,6 +4,7 @@ import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseH
import { defaultPaymentInputOptions, InputBlockType } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { stripePaymentForm } from '@/test/utils/selectorUtils'
+import { env } from '@typebot.io/env'
test.describe('Payment input block', () => {
test('Can configure Stripe account', async ({ page }) => {
@@ -23,21 +24,15 @@ test.describe('Payment input block', () => {
await page.getByRole('button', { name: 'Select an account' }).click()
await page.click('text=Connect new')
await page.fill('[placeholder="Typebot"]', 'My Stripe Account')
- await page.fill(
- '[placeholder="sk_test_..."]',
- process.env.STRIPE_SECRET_KEY ?? ''
- )
- await page.fill(
- '[placeholder="sk_live_..."]',
- process.env.STRIPE_SECRET_KEY ?? ''
- )
+ await page.fill('[placeholder="sk_test_..."]', env.STRIPE_SECRET_KEY ?? '')
+ await page.fill('[placeholder="sk_live_..."]', env.STRIPE_SECRET_KEY ?? '')
await page.fill(
'[placeholder="pk_test_..."]',
- process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
+ env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
)
await page.fill(
'[placeholder="pk_live_..."]',
- process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
+ env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
)
await expect(page.locator('button >> text="Connect"')).toBeEnabled()
await page.click('button >> text="Connect"')
diff --git a/apps/builder/src/features/blocks/integrations/sendEmail/components/SendEmailSettings.tsx b/apps/builder/src/features/blocks/integrations/sendEmail/components/SendEmailSettings.tsx
index 9c001a25751..6082d369bfc 100644
--- a/apps/builder/src/features/blocks/integrations/sendEmail/components/SendEmailSettings.tsx
+++ b/apps/builder/src/features/blocks/integrations/sendEmail/components/SendEmailSettings.tsx
@@ -10,7 +10,7 @@ import {
import { CodeEditor } from '@/components/inputs/CodeEditor'
import { SendEmailOptions, Variable } from '@typebot.io/schemas'
import React from 'react'
-import { env, isNotEmpty } from '@typebot.io/lib'
+import { isNotEmpty } from '@typebot.io/lib'
import { SmtpConfigModal } from './SmtpConfigModal'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
@@ -18,6 +18,7 @@ import { CredentialsDropdown } from '@/features/credentials/components/Credentia
import { TextInput, Textarea } from '@/components/inputs'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
+import { env } from '@typebot.io/env'
type Props = {
options: SendEmailOptions
@@ -117,9 +118,9 @@ export const SendEmailSettings = ({ options, onOptionsChange }: Props) => {
currentCredentialsId={options.credentialsId}
onCredentialsSelect={handleCredentialsSelect}
onCreateNewClick={onOpen}
- defaultCredentialLabel={env('SMTP_FROM')
- ?.match(/<(.*)>/)
- ?.pop()}
+ defaultCredentialLabel={env.NEXT_PUBLIC_SMTP_FROM?.match(
+ /<(.*)>/
+ )?.pop()}
/>
)}
diff --git a/apps/builder/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts b/apps/builder/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
index 266a0580b67..41513c36997 100644
--- a/apps/builder/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
+++ b/apps/builder/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
@@ -2,17 +2,18 @@ import test, { expect } from '@playwright/test'
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
import { createId } from '@paralleldrive/cuid2'
import { getTestAsset } from '@/test/utils/playwright'
+import { env } from '@typebot.io/env'
const typebotId = createId()
test.describe('Send email block', () => {
test('its configuration should work', async ({ page }) => {
if (
- !process.env.SMTP_USERNAME ||
- !process.env.SMTP_PORT ||
- !process.env.SMTP_HOST ||
- !process.env.SMTP_PASSWORD ||
- !process.env.NEXT_PUBLIC_SMTP_FROM
+ !env.SMTP_USERNAME ||
+ !env.SMTP_PORT ||
+ !env.SMTP_HOST ||
+ !env.SMTP_PASSWORD ||
+ !env.NEXT_PUBLIC_SMTP_FROM
)
throw new Error('SMTP_ env vars are missing')
await importTypebotInDatabase(
@@ -30,21 +31,18 @@ test.describe('Send email block', () => {
await expect(createButton).toBeDisabled()
await page.fill(
'[placeholder="notifications@provider.com"]',
- process.env.SMTP_USERNAME
+ env.SMTP_USERNAME
)
await page.fill('[placeholder="John Smith"]', 'John Smith')
- await page.fill('[placeholder="mail.provider.com"]', process.env.SMTP_HOST)
- await page.fill(
- '[placeholder="user@provider.com"]',
- process.env.SMTP_USERNAME
- )
- await page.fill('[type="password"]', process.env.SMTP_PASSWORD)
- await page.fill('input[role="spinbutton"]', process.env.SMTP_PORT)
+ await page.fill('[placeholder="mail.provider.com"]', env.SMTP_HOST)
+ await page.fill('[placeholder="user@provider.com"]', env.SMTP_USERNAME)
+ await page.fill('[type="password"]', env.SMTP_PASSWORD)
+ await page.fill('input[role="spinbutton"]', env.SMTP_PORT.toString())
await expect(createButton).toBeEnabled()
await createButton.click()
await expect(
- page.locator(`button >> text=${process.env.SMTP_USERNAME}`)
+ page.locator(`button >> text=${env.SMTP_USERNAME}`)
).toBeVisible()
await page.fill(
diff --git a/apps/builder/src/features/blocks/integrations/webhook/webhook.spec.ts b/apps/builder/src/features/blocks/integrations/webhook/webhook.spec.ts
index e0cd764c4dd..60ed9c0d076 100644
--- a/apps/builder/src/features/blocks/integrations/webhook/webhook.spec.ts
+++ b/apps/builder/src/features/blocks/integrations/webhook/webhook.spec.ts
@@ -7,6 +7,7 @@ import { HttpMethod } from '@typebot.io/schemas/features/blocks/integrations/web
import { createId } from '@paralleldrive/cuid2'
import { getTestAsset } from '@/test/utils/playwright'
import { apiToken } from '@typebot.io/lib/playwright/databaseSetup'
+import { env } from '@typebot.io/env'
test.describe('Builder', () => {
test('easy configuration should work', async ({ page }) => {
@@ -22,7 +23,7 @@ test.describe('Builder', () => {
await page.click('text=Configure...')
await page.fill(
'input[placeholder="Paste webhook URL..."]',
- `${process.env.NEXTAUTH_URL}/api/mock/webhook-easy-config`
+ `${env.NEXTAUTH_URL}/api/mock/webhook-easy-config`
)
await page.click('text=Test the request')
await expect(page.locator('div[role="textbox"] >> nth=-1')).toContainText(
@@ -45,7 +46,7 @@ test.describe('Builder', () => {
await page.click('text=Configure...')
await page.fill(
'input[placeholder="Paste webhook URL..."]',
- `${process.env.NEXTAUTH_URL}/api/mock/webhook`
+ `${env.NEXTAUTH_URL}/api/mock/webhook`
)
await page.click('text=Advanced configuration')
await page.getByRole('button', { name: 'GET' }).click()
diff --git a/apps/builder/src/features/collaboration/hooks/useInvitations.ts b/apps/builder/src/features/collaboration/hooks/useInvitations.ts
index 37c1540e013..d89cae11341 100644
--- a/apps/builder/src/features/collaboration/hooks/useInvitations.ts
+++ b/apps/builder/src/features/collaboration/hooks/useInvitations.ts
@@ -1,7 +1,7 @@
import { fetcher } from '@/helpers/fetcher'
import { Invitation } from '@typebot.io/prisma'
import useSWR from 'swr'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
export const useInvitations = ({
typebotId,
@@ -14,7 +14,7 @@ export const useInvitations = ({
typebotId ? `/api/typebots/${typebotId}/invitations` : null,
fetcher,
{
- dedupingInterval: env('E2E_TEST') === 'true' ? 0 : undefined,
+ dedupingInterval: env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined,
}
)
if (error) onError(error)
diff --git a/apps/builder/src/features/dashboard/api/getAppVersionProcedure.ts b/apps/builder/src/features/dashboard/api/getAppVersionProcedure.ts
index 2371190cae8..2a8e9b1c6fa 100644
--- a/apps/builder/src/features/dashboard/api/getAppVersionProcedure.ts
+++ b/apps/builder/src/features/dashboard/api/getAppVersionProcedure.ts
@@ -1,5 +1,6 @@
import { publicProcedure } from '@/helpers/server/trpc'
+import { env } from '@typebot.io/env'
export const getAppVersionProcedure = publicProcedure.query(async () => {
- return { commitSha: process.env.VERCEL_GIT_COMMIT_SHA }
+ return { commitSha: env.VERCEL_GIT_COMMIT_SHA }
})
diff --git a/apps/builder/src/features/folders/hooks/useFolders.ts b/apps/builder/src/features/folders/hooks/useFolders.ts
index a19b0958c62..8de976f8536 100644
--- a/apps/builder/src/features/folders/hooks/useFolders.ts
+++ b/apps/builder/src/features/folders/hooks/useFolders.ts
@@ -2,7 +2,7 @@ import { fetcher } from '@/helpers/fetcher'
import { DashboardFolder } from '@typebot.io/prisma'
import { stringify } from 'qs'
import useSWR from 'swr'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
export const useFolders = ({
parentId,
@@ -18,7 +18,7 @@ export const useFolders = ({
workspaceId ? `/api/folders?${params}` : null,
fetcher,
{
- dedupingInterval: env('E2E_TEST') === 'true' ? 0 : undefined,
+ dedupingInterval: env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined,
}
)
if (error) onError(error)
diff --git a/apps/builder/src/features/publish/components/SharePage.tsx b/apps/builder/src/features/publish/components/SharePage.tsx
index cd0df7e28f0..47c2e86fa0a 100644
--- a/apps/builder/src/features/publish/components/SharePage.tsx
+++ b/apps/builder/src/features/publish/components/SharePage.tsx
@@ -13,7 +13,7 @@ import {
Text,
} from '@chakra-ui/react'
import { Plan } from '@typebot.io/prisma'
-import { isDefined, getViewerUrl, isNotDefined, env } from '@typebot.io/lib'
+import { isDefined, isNotDefined } from '@typebot.io/lib'
import { isPublicDomainAvailableQuery } from '../queries/isPublicDomainAvailableQuery'
import { EditableUrl } from './EditableUrl'
import { integrationsList } from './embeds/EmbedButton'
@@ -25,6 +25,7 @@ import { CustomDomainsDropdown } from '@/features/customDomains/components/Custo
import { TypebotHeader } from '@/features/editor/components/TypebotHeader'
import { parseDefaultPublicId } from '../helpers/parseDefaultPublicId'
import { useI18n } from '@/locales'
+import { env } from '@typebot.io/env'
export const SharePage = () => {
const t = useI18n()
@@ -97,7 +98,7 @@ export const SharePage = () => {
{typebot && (
{
)}
{isNotDefined(typebot?.customDomain) &&
- env('VERCEL_VIEWER_PROJECT_NAME') ? (
+ env.NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME ? (
<>
{isProPlan(workspace) ? (
diff --git a/apps/builder/src/features/publish/components/embeds/modals/IframeModal/IframeSnippet.tsx b/apps/builder/src/features/publish/components/embeds/modals/IframeModal/IframeSnippet.tsx
index bdbb1805b21..a601e15efa7 100644
--- a/apps/builder/src/features/publish/components/embeds/modals/IframeModal/IframeSnippet.tsx
+++ b/apps/builder/src/features/publish/components/embeds/modals/IframeModal/IframeSnippet.tsx
@@ -1,6 +1,6 @@
import { FlexProps } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
-import { env, getViewerUrl } from '@typebot.io/lib'
+import { getViewerUrl } from '@typebot.io/lib'
import { CodeEditor } from '@/components/inputs/CodeEditor'
import prettier from 'prettier/standalone'
import parserHtml from 'prettier/parser-html'
@@ -13,9 +13,7 @@ type Props = {
export const IframeSnippet = ({ widthLabel, heightLabel }: Props) => {
const { typebot } = useTypebot()
- const src = `${env('VIEWER_INTERNAL_URL') ?? getViewerUrl()}/${
- typebot?.publicId
- }`
+ const src = `${getViewerUrl()}/${typebot?.publicId}`
const code = prettier.format(
``,
{ parser: 'html', plugins: [parserHtml] }
diff --git a/apps/builder/src/features/publish/components/embeds/modals/NotionModal.tsx b/apps/builder/src/features/publish/components/embeds/modals/NotionModal.tsx
index 658ad57c0a8..4eaa289f8fd 100644
--- a/apps/builder/src/features/publish/components/embeds/modals/NotionModal.tsx
+++ b/apps/builder/src/features/publish/components/embeds/modals/NotionModal.tsx
@@ -18,7 +18,7 @@ import {
Text,
Stack,
} from '@chakra-ui/react'
-import { env, getViewerUrl } from '@typebot.io/lib'
+import { getViewerUrl } from '@typebot.io/lib'
import { ModalProps } from '../EmbedButton'
export const NotionModal = ({
@@ -49,16 +49,12 @@ export const NotionModal = ({
diff --git a/apps/builder/src/features/publish/components/embeds/modals/WordpressModal/instructions/WordpressStandardInstructions.tsx b/apps/builder/src/features/publish/components/embeds/modals/WordpressModal/instructions/WordpressStandardInstructions.tsx
index b41f335f462..6fa1db45cb5 100644
--- a/apps/builder/src/features/publish/components/embeds/modals/WordpressModal/instructions/WordpressStandardInstructions.tsx
+++ b/apps/builder/src/features/publish/components/embeds/modals/WordpressModal/instructions/WordpressStandardInstructions.tsx
@@ -12,7 +12,7 @@ import {
import { useState } from 'react'
import { StandardSettings } from '../../../settings/StandardSettings'
import { isCloudProdInstance } from '@/helpers/isCloudProdInstance'
-import { env, getViewerUrl } from '@typebot.io/lib'
+import { getViewerUrl } from '@typebot.io/lib'
type Props = {
publicId: string
@@ -76,9 +76,7 @@ const parseWordpressShortcode = ({
publicId: string
}) => {
return `[typebot typebot="${publicId}"${
- isCloudProdInstance
- ? ''
- : ` host="${env('VIEWER_INTERNAL_URL') ?? getViewerUrl()}"`
+ isCloudProdInstance ? '' : ` host="${getViewerUrl()}"`
}${width ? ` width="${width}"` : ''}${height ? ` height="${height}"` : ''}]
`
}
diff --git a/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts b/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts
index f67fbaae278..d90d284405b 100644
--- a/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts
+++ b/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts
@@ -1,7 +1,7 @@
import { BotProps } from '@typebot.io/nextjs'
import parserBabel from 'prettier/parser-babel'
import prettier from 'prettier/standalone'
-import { env, getViewerUrl, isDefined } from '@typebot.io/lib'
+import { getViewerUrl, isDefined } from '@typebot.io/lib'
import { Typebot } from '@typebot.io/schemas'
import { isCloudProdInstance } from '@/helpers/isCloudProdInstance'
import packageJson from '../../../../../../../../packages/embeds/js/package.json'
@@ -58,7 +58,7 @@ export const parseApiHost = (
customDomain: Typebot['customDomain'] | undefined
) => {
if (customDomain) return new URL(`https://${customDomain}`).origin
- return env('VIEWER_INTERNAL_URL') ?? getViewerUrl()
+ return getViewerUrl()
}
export const parseApiHostValue = (
diff --git a/apps/builder/src/features/telemetry/api/processTelemetryEvent.ts b/apps/builder/src/features/telemetry/api/processTelemetryEvent.ts
index 4660559a1a0..34e07b4ea7a 100644
--- a/apps/builder/src/features/telemetry/api/processTelemetryEvent.ts
+++ b/apps/builder/src/features/telemetry/api/processTelemetryEvent.ts
@@ -4,6 +4,7 @@ import { PostHog } from 'posthog-node'
import { TRPCError } from '@trpc/server'
import got from 'got'
import { authenticatedProcedure } from '@/helpers/server/trpc'
+import { env } from '@typebot.io/env'
// Only used for the cloud version of Typebot. It's the way it processes telemetry events and inject it to thrid-party services.
export const processTelemetryEvent = authenticatedProcedure
@@ -26,17 +27,17 @@ export const processTelemetryEvent = authenticatedProcedure
})
)
.query(async ({ input: { events }, ctx: { user } }) => {
- if (user.email !== process.env.ADMIN_EMAIL)
+ if (user.email !== env.ADMIN_EMAIL)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Only app admin can process telemetry events',
})
- if (!process.env.POSTHOG_API_KEY)
+ if (!env.POSTHOG_API_KEY)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Server does not have POSTHOG_API_KEY configured',
})
- const client = new PostHog(process.env.POSTHOG_API_KEY, {
+ const client = new PostHog(env.POSTHOG_API_KEY, {
host: 'https://eu.posthog.com',
})
@@ -65,11 +66,8 @@ export const processTelemetryEvent = authenticatedProcedure
groupKey: event.typebotId,
properties: { name: event.data.name },
})
- if (
- event.name === 'User created' &&
- process.env.USER_CREATED_WEBHOOK_URL
- ) {
- await got.post(process.env.USER_CREATED_WEBHOOK_URL, {
+ if (event.name === 'User created' && env.USER_CREATED_WEBHOOK_URL) {
+ await got.post(env.USER_CREATED_WEBHOOK_URL, {
json: {
email: event.data.email,
name: event.data.name ? event.data.name.split(' ')[0] : undefined,
diff --git a/apps/builder/src/features/theme/components/general/FontSelector.tsx b/apps/builder/src/features/theme/components/general/FontSelector.tsx
index a991ce6c889..8462804dbad 100644
--- a/apps/builder/src/features/theme/components/general/FontSelector.tsx
+++ b/apps/builder/src/features/theme/components/general/FontSelector.tsx
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'
import { Text, HStack } from '@chakra-ui/react'
-import { env, isEmpty } from '@typebot.io/lib'
import { AutocompleteInput } from '@/components/inputs/AutocompleteInput'
+import { env } from '@typebot.io/env'
type FontSelectorProps = {
activeFont?: string
@@ -20,11 +20,9 @@ export const FontSelector = ({
}, [])
const fetchPopularFonts = async () => {
- if (isEmpty(env('GOOGLE_API_KEY'))) return []
+ if (!env.NEXT_PUBLIC_GOOGLE_API_KEY) return []
const response = await fetch(
- `https://www.googleapis.com/webfonts/v1/webfonts?key=${env(
- 'GOOGLE_API_KEY'
- )}&sort=popularity`
+ `https://www.googleapis.com/webfonts/v1/webfonts?key=${env.NEXT_PUBLIC_GOOGLE_API_KEY}&sort=popularity`
)
return (await response.json()).items.map(
(item: { family: string }) => item.family
diff --git a/apps/builder/src/features/typebot/helpers/isReadTypebotForbidden.ts b/apps/builder/src/features/typebot/helpers/isReadTypebotForbidden.ts
index 7cdee98f9e6..c4719cc859c 100644
--- a/apps/builder/src/features/typebot/helpers/isReadTypebotForbidden.ts
+++ b/apps/builder/src/features/typebot/helpers/isReadTypebotForbidden.ts
@@ -1,4 +1,5 @@
import prisma from '@/lib/prisma'
+import { env } from '@typebot.io/env'
import { CollaboratorsOnTypebots, User } from '@typebot.io/prisma'
import { Typebot } from '@typebot.io/schemas'
@@ -9,7 +10,7 @@ export const isReadTypebotForbidden = async (
user: Pick
) => {
if (
- process.env.ADMIN_EMAIL === user.email ||
+ env.ADMIN_EMAIL === user.email ||
typebot.collaborators.find(
(collaborator) => collaborator.userId === user.id
)
diff --git a/apps/builder/src/features/workspace/helpers/parseWorkspaceDefaultPlan.ts b/apps/builder/src/features/workspace/helpers/parseWorkspaceDefaultPlan.ts
index 442bf3f6b22..f36aacb61a5 100644
--- a/apps/builder/src/features/workspace/helpers/parseWorkspaceDefaultPlan.ts
+++ b/apps/builder/src/features/workspace/helpers/parseWorkspaceDefaultPlan.ts
@@ -1,8 +1,9 @@
+import { env } from '@typebot.io/env'
import { Plan } from '@typebot.io/prisma'
export const parseWorkspaceDefaultPlan = (userEmail: string) => {
- if (process.env.ADMIN_EMAIL === userEmail) return Plan.UNLIMITED
- const defaultPlan = process.env.DEFAULT_WORKSPACE_PLAN as Plan | undefined
+ if (env.ADMIN_EMAIL === userEmail) return Plan.UNLIMITED
+ const defaultPlan = env.DEFAULT_WORKSPACE_PLAN as Plan | undefined
if (defaultPlan && Object.values(Plan).includes(defaultPlan))
return defaultPlan
return Plan.FREE
diff --git a/apps/builder/src/features/workspace/hooks/useMembers.ts b/apps/builder/src/features/workspace/hooks/useMembers.ts
index ddd91906475..dd2c2717919 100644
--- a/apps/builder/src/features/workspace/hooks/useMembers.ts
+++ b/apps/builder/src/features/workspace/hooks/useMembers.ts
@@ -1,7 +1,7 @@
import { WorkspaceInvitation } from '@typebot.io/prisma'
import { fetcher } from '@/helpers/fetcher'
import useSWR from 'swr'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
import { Member } from '../types'
export const useMembers = ({ workspaceId }: { workspaceId?: string }) => {
@@ -9,7 +9,7 @@ export const useMembers = ({ workspaceId }: { workspaceId?: string }) => {
{ members: Member[]; invitations: WorkspaceInvitation[] },
Error
>(workspaceId ? `/api/workspaces/${workspaceId}/members` : null, fetcher, {
- dedupingInterval: env('E2E_TEST') === 'true' ? 0 : undefined,
+ dedupingInterval: env.NEXT_PUBLIC_E2E_TEST ? 0 : undefined,
})
return {
members: data?.members ?? [],
diff --git a/apps/builder/src/helpers/databaseRules.ts b/apps/builder/src/helpers/databaseRules.ts
index f658e594e86..11e5f327c27 100644
--- a/apps/builder/src/helpers/databaseRules.ts
+++ b/apps/builder/src/helpers/databaseRules.ts
@@ -7,14 +7,14 @@ import {
} from '@typebot.io/prisma'
import prisma from '@/lib/prisma'
import { NextApiResponse } from 'next'
-import { env, isNotEmpty } from '@typebot.io/lib'
import { forbidden } from '@typebot.io/lib/api'
+import { env } from '@typebot.io/env'
export const canWriteTypebots = (
typebotIds: string[] | string,
user: Pick
): Prisma.TypebotWhereInput =>
- isNotEmpty(env('E2E_TEST'))
+ env.NEXT_PUBLIC_E2E_TEST
? { id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds } }
: {
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
@@ -40,7 +40,7 @@ export const canReadTypebots = (
) => ({
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
workspace:
- user.email === process.env.ADMIN_EMAIL || isNotEmpty(env('E2E_TEST'))
+ user.email === env.ADMIN_EMAIL || env.NEXT_PUBLIC_E2E_TEST
? undefined
: {
members: {
diff --git a/apps/builder/src/helpers/deleteFilesFromBucket.ts b/apps/builder/src/helpers/deleteFilesFromBucket.ts
index 77b7fb8e188..b6983d5ee16 100644
--- a/apps/builder/src/helpers/deleteFilesFromBucket.ts
+++ b/apps/builder/src/helpers/deleteFilesFromBucket.ts
@@ -1,3 +1,4 @@
+import { env } from '@typebot.io/env'
import { Client } from 'minio'
export const deleteFilesFromBucket = async ({
@@ -5,32 +6,26 @@ export const deleteFilesFromBucket = async ({
}: {
urls: string[]
}): Promise => {
- if (
- !process.env.S3_ENDPOINT ||
- !process.env.S3_ACCESS_KEY ||
- !process.env.S3_SECRET_KEY
- )
+ if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
throw new Error(
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY'
)
- const useSSL =
- process.env.S3_SSL && process.env.S3_SSL === 'false' ? false : true
const minioClient = new Client({
- endPoint: process.env.S3_ENDPOINT,
- port: process.env.S3_PORT ? parseInt(process.env.S3_PORT) : undefined,
- useSSL,
- accessKey: process.env.S3_ACCESS_KEY,
- secretKey: process.env.S3_SECRET_KEY,
- region: process.env.S3_REGION,
+ endPoint: env.S3_ENDPOINT,
+ port: env.S3_PORT,
+ useSSL: env.S3_SSL,
+ accessKey: env.S3_ACCESS_KEY,
+ secretKey: env.S3_SECRET_KEY,
+ region: env.S3_REGION,
})
- const bucket = process.env.S3_BUCKET ?? 'typebot'
+ const bucket = env.S3_BUCKET ?? 'typebot'
return minioClient.removeObjects(
bucket,
urls
- .filter((url) => url.includes(process.env.S3_ENDPOINT as string))
+ .filter((url) => url.includes(env.S3_ENDPOINT as string))
.map((url) => url.split(`/${bucket}/`)[1])
)
}
diff --git a/apps/builder/src/lib/googleSheets.ts b/apps/builder/src/lib/googleSheets.ts
index 3cf64c191bb..580ccce5801 100644
--- a/apps/builder/src/lib/googleSheets.ts
+++ b/apps/builder/src/lib/googleSheets.ts
@@ -4,11 +4,12 @@ import { GoogleSheetsCredentials } from '@typebot.io/schemas'
import { isDefined } from '@typebot.io/lib'
import { decrypt, encrypt } from '@typebot.io/lib/api'
import prisma from './prisma'
+import { env } from '@typebot.io/env'
export const oauth2Client = new OAuth2Client(
- process.env.GOOGLE_CLIENT_ID,
- process.env.GOOGLE_CLIENT_SECRET,
- `${process.env.NEXTAUTH_URL}/api/credentials/google-sheets/callback`
+ env.GOOGLE_CLIENT_ID,
+ env.GOOGLE_CLIENT_SECRET,
+ `${env.NEXTAUTH_URL}/api/credentials/google-sheets/callback`
)
export const getAuthenticatedGoogleClient = async (
diff --git a/apps/builder/src/lib/prisma.ts b/apps/builder/src/lib/prisma.ts
index 13abf46c6e2..d91fcca1e55 100644
--- a/apps/builder/src/lib/prisma.ts
+++ b/apps/builder/src/lib/prisma.ts
@@ -2,6 +2,7 @@
* Instantiates a single instance PrismaClient and save it on the global object.
* @link https://www.prisma.io/docs/support/help-articles/nextjs-prisma-client-dev-practices
*/
+import { env } from '@typebot.io/env'
import { PrismaClient } from '@typebot.io/prisma'
const prismaGlobal = global as typeof global & {
@@ -11,10 +12,10 @@ const prismaGlobal = global as typeof global & {
const prisma: PrismaClient =
prismaGlobal.prisma ||
new PrismaClient({
- log: process.env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
+ log: env.NODE_ENV === 'development' ? ['error', 'warn'] : ['error'],
})
-if (process.env.NODE_ENV !== 'production') {
+if (env.NODE_ENV !== 'production') {
prismaGlobal.prisma = prisma
}
diff --git a/apps/builder/src/lib/trpc.ts b/apps/builder/src/lib/trpc.ts
index 9892bdeb6c0..b530719556e 100644
--- a/apps/builder/src/lib/trpc.ts
+++ b/apps/builder/src/lib/trpc.ts
@@ -2,10 +2,9 @@ import { createTRPCProxyClient, httpBatchLink, loggerLink } from '@trpc/client'
import { createTRPCNext } from '@trpc/next'
import type { AppRouter } from '../helpers/server/routers/v1/trpcRouter'
import superjson from 'superjson'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
-const getBaseUrl = () =>
- typeof window !== 'undefined' ? '' : process.env.NEXTAUTH_URL
+const getBaseUrl = () => (typeof window !== 'undefined' ? '' : env.NEXTAUTH_URL)
export const trpc = createTRPCNext({
config() {
@@ -36,5 +35,5 @@ export const trpcVanilla = createTRPCProxyClient({
})
export const defaultQueryOptions = {
- refetchOnMount: env('E2E_TEST') === 'true',
+ refetchOnMount: env.NEXT_PUBLIC_E2E_TEST,
}
diff --git a/apps/builder/src/pages/_document.tsx b/apps/builder/src/pages/_document.tsx
index 947090ac62b..21f232da28e 100644
--- a/apps/builder/src/pages/_document.tsx
+++ b/apps/builder/src/pages/_document.tsx
@@ -12,7 +12,7 @@ const Document = () => (
/>
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
-
+
diff --git a/apps/builder/src/pages/api/auth/[...nextauth].ts b/apps/builder/src/pages/api/auth/[...nextauth].ts
index 8873892d7ab..4b9c1e93af7 100644
--- a/apps/builder/src/pages/api/auth/[...nextauth].ts
+++ b/apps/builder/src/pages/api/auth/[...nextauth].ts
@@ -10,139 +10,114 @@ import { Provider } from 'next-auth/providers'
import { NextApiRequest, NextApiResponse } from 'next'
import { customAdapter } from '../../../features/auth/api/customAdapter'
import { User } from '@typebot.io/prisma'
-import { env, getAtPath, isDefined, isNotEmpty } from '@typebot.io/lib'
+import { getAtPath, isDefined } from '@typebot.io/lib'
import { mockedUser } from '@/features/auth/mockedUser'
import { getNewUserInvitations } from '@/features/auth/helpers/getNewUserInvitations'
import { sendVerificationRequest } from '@/features/auth/helpers/sendVerificationRequest'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis/nodejs'
import got from 'got'
+import { env } from '@typebot.io/env'
const providers: Provider[] = []
let rateLimit: Ratelimit | undefined
-if (
- process.env.UPSTASH_REDIS_REST_URL &&
- process.env.UPSTASH_REDIS_REST_TOKEN
-) {
+if (env.UPSTASH_REDIS_REST_URL && env.UPSTASH_REDIS_REST_TOKEN) {
rateLimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(1, '60 s'),
})
}
-if (
- isNotEmpty(process.env.GITHUB_CLIENT_ID) &&
- isNotEmpty(process.env.GITHUB_CLIENT_SECRET)
-)
+if (env.GITHUB_CLIENT_ID && env.GITHUB_CLIENT_SECRET)
providers.push(
GitHubProvider({
- clientId: process.env.GITHUB_CLIENT_ID,
- clientSecret: process.env.GITHUB_CLIENT_SECRET,
+ clientId: env.GITHUB_CLIENT_ID,
+ clientSecret: env.GITHUB_CLIENT_SECRET,
})
)
-if (isNotEmpty(env('SMTP_FROM')) && process.env.SMTP_AUTH_DISABLED !== 'true')
+if (env.NEXT_PUBLIC_SMTP_FROM && env.SMTP_AUTH_DISABLED)
providers.push(
EmailProvider({
server: {
- host: process.env.SMTP_HOST,
- port: process.env.SMTP_PORT ? Number(process.env.SMTP_PORT) : 25,
- secure: process.env.SMTP_SECURE
- ? process.env.SMTP_SECURE === 'true'
- : false,
+ host: env.SMTP_HOST,
+ port: env.SMTP_PORT ? Number(env.SMTP_PORT) : 25,
+ secure: env.SMTP_SECURE ? env.SMTP_SECURE : false,
auth: {
- user: process.env.SMTP_USERNAME,
- pass: process.env.SMTP_PASSWORD,
+ user: env.SMTP_USERNAME,
+ pass: env.SMTP_PASSWORD,
},
},
- from: env('SMTP_FROM'),
+ from: env.NEXT_PUBLIC_SMTP_FROM,
sendVerificationRequest,
})
)
-if (
- isNotEmpty(process.env.GOOGLE_CLIENT_ID) &&
- isNotEmpty(process.env.GOOGLE_CLIENT_SECRET)
-)
+if (env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET)
providers.push(
GoogleProvider({
- clientId: process.env.GOOGLE_CLIENT_ID,
- clientSecret: process.env.GOOGLE_CLIENT_SECRET,
+ clientId: env.GOOGLE_CLIENT_ID,
+ clientSecret: env.GOOGLE_CLIENT_SECRET,
})
)
-if (
- isNotEmpty(process.env.FACEBOOK_CLIENT_ID) &&
- isNotEmpty(process.env.FACEBOOK_CLIENT_SECRET)
-)
+if (env.FACEBOOK_CLIENT_ID && env.FACEBOOK_CLIENT_SECRET)
providers.push(
FacebookProvider({
- clientId: process.env.FACEBOOK_CLIENT_ID,
- clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
+ clientId: env.FACEBOOK_CLIENT_ID,
+ clientSecret: env.FACEBOOK_CLIENT_SECRET,
})
)
-if (
- isNotEmpty(process.env.GITLAB_CLIENT_ID) &&
- isNotEmpty(process.env.GITLAB_CLIENT_SECRET)
-) {
- const BASE_URL = process.env.GITLAB_BASE_URL || 'https://gitlab.com'
+if (env.GITLAB_CLIENT_ID && env.GITLAB_CLIENT_SECRET) {
+ const BASE_URL = env.GITLAB_BASE_URL || 'https://gitlab.com'
providers.push(
GitlabProvider({
- clientId: process.env.GITLAB_CLIENT_ID,
- clientSecret: process.env.GITLAB_CLIENT_SECRET,
+ clientId: env.GITLAB_CLIENT_ID,
+ clientSecret: env.GITLAB_CLIENT_SECRET,
authorization: `${BASE_URL}/oauth/authorize?scope=read_api`,
token: `${BASE_URL}/oauth/token`,
userinfo: `${BASE_URL}/api/v4/user`,
- name: process.env.GITLAB_NAME || 'GitLab',
+ name: env.GITLAB_NAME || 'GitLab',
})
)
}
if (
- isNotEmpty(process.env.AZURE_AD_CLIENT_ID) &&
- isNotEmpty(process.env.AZURE_AD_CLIENT_SECRET) &&
- isNotEmpty(process.env.AZURE_AD_TENANT_ID)
+ env.AZURE_AD_CLIENT_ID &&
+ env.AZURE_AD_CLIENT_SECRET &&
+ env.AZURE_AD_TENANT_ID
) {
providers.push(
AzureADProvider({
- clientId: process.env.AZURE_AD_CLIENT_ID,
- clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
- tenantId: process.env.AZURE_AD_TENANT_ID,
+ clientId: env.AZURE_AD_CLIENT_ID,
+ clientSecret: env.AZURE_AD_CLIENT_SECRET,
+ tenantId: env.AZURE_AD_TENANT_ID,
})
)
}
-if (isNotEmpty(process.env.CUSTOM_OAUTH_WELL_KNOWN_URL)) {
+if (env.CUSTOM_OAUTH_WELL_KNOWN_URL) {
providers.push({
id: 'custom-oauth',
- name: process.env.CUSTOM_OAUTH_NAME ?? 'Custom OAuth',
+ name: env.CUSTOM_OAUTH_NAME ?? 'Custom OAuth',
type: 'oauth',
authorization: {
params: {
- scope: process.env.CUSTOM_OAUTH_SCOPE ?? 'openid profile email',
+ scope: env.CUSTOM_OAUTH_SCOPE ?? 'openid profile email',
},
},
- clientId: process.env.CUSTOM_OAUTH_CLIENT_ID,
- clientSecret: process.env.CUSTOM_OAUTH_CLIENT_SECRET,
- wellKnown: process.env.CUSTOM_OAUTH_WELL_KNOWN_URL,
+ clientId: env.CUSTOM_OAUTH_CLIENT_ID,
+ clientSecret: env.CUSTOM_OAUTH_CLIENT_SECRET,
+ wellKnown: env.CUSTOM_OAUTH_WELL_KNOWN_URL,
profile(profile) {
return {
- id: getAtPath(profile, process.env.CUSTOM_OAUTH_USER_ID_PATH ?? 'id'),
- name: getAtPath(
- profile,
- process.env.CUSTOM_OAUTH_USER_NAME_PATH ?? 'name'
- ),
- email: getAtPath(
- profile,
- process.env.CUSTOM_OAUTH_USER_EMAIL_PATH ?? 'email'
- ),
- image: getAtPath(
- profile,
- process.env.CUSTOM_OAUTH_USER_IMAGE_PATH ?? 'image'
- ),
+ id: getAtPath(profile, env.CUSTOM_OAUTH_USER_ID_PATH ?? 'id'),
+ name: getAtPath(profile, env.CUSTOM_OAUTH_USER_NAME_PATH ?? 'name'),
+ email: getAtPath(profile, env.CUSTOM_OAUTH_USER_EMAIL_PATH ?? 'email'),
+ image: getAtPath(profile, env.CUSTOM_OAUTH_USER_IMAGE_PATH ?? 'image'),
} as User
},
})
@@ -150,16 +125,14 @@ if (isNotEmpty(process.env.CUSTOM_OAUTH_WELL_KNOWN_URL)) {
export const authOptions: AuthOptions = {
adapter: customAdapter(prisma),
- secret: process.env.ENCRYPTION_SECRET,
+ secret: env.ENCRYPTION_SECRET,
providers,
session: {
strategy: 'database',
},
pages: {
signIn: '/signin',
- newUser: process.env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID
- ? '/onboarding'
- : undefined,
+ newUser: env.NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID ? '/onboarding' : undefined,
},
callbacks: {
session: async ({ session, user }) => {
@@ -181,7 +154,7 @@ export const authOptions: AuthOptions = {
if (disposableEmailDomains.includes(user.email.split('@')[1]))
return false
}
- if (process.env.DISABLE_SIGNUP === 'true' && isNewUser && user.email) {
+ if (env.DISABLE_SIGNUP && isNewUser && user.email) {
const { invitations, workspaceInvitations } =
await getNewUserInvitations(prisma, user.email)
if (invitations.length === 0 && workspaceInvitations.length === 0)
@@ -201,7 +174,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const isMockingSession =
req.method === 'GET' &&
req.url === '/api/auth/session' &&
- env('E2E_TEST') === 'true'
+ env.NEXT_PUBLIC_E2E_TEST
if (isMockingSession) return res.send({ user: mockedUser })
const requestIsFromCompanyFirewall = req.method === 'HEAD'
if (requestIsFromCompanyFirewall) return res.status(200).end()
@@ -248,7 +221,7 @@ const getUserGroups = async (account: Account): Promise => {
): Promise<{ full_path: string }[]> => {
const res = await fetch(
`${
- process.env.GITLAB_BASE_URL || 'https://gitlab.com'
+ env.GITLAB_BASE_URL || 'https://gitlab.com'
}/api/v4/groups?per_page=100&page=${page}`,
{ headers: { Authorization: `Bearer ${accessToken}` } }
)
@@ -269,7 +242,7 @@ const getUserGroups = async (account: Account): Promise => {
const getRequiredGroups = (provider: string): string[] => {
switch (provider) {
case 'gitlab':
- return process.env.GITLAB_REQUIRED_GROUPS?.split(',') || []
+ return env.GITLAB_REQUIRED_GROUPS ?? []
default:
return []
}
diff --git a/apps/builder/src/pages/api/credentials/google-sheets/callback.ts b/apps/builder/src/pages/api/credentials/google-sheets/callback.ts
index 93f0f94f8a3..b3d56ea4b45 100644
--- a/apps/builder/src/pages/api/credentials/google-sheets/callback.ts
+++ b/apps/builder/src/pages/api/credentials/google-sheets/callback.ts
@@ -6,6 +6,7 @@ import { stringify } from 'querystring'
import { badRequest, encrypt, notAuthenticated } from '@typebot.io/lib/api'
import { oauth2Client } from '@/lib/googleSheets'
import { getAuthenticatedUser } from '@/features/auth/helpers/getAuthenticatedUser'
+import { env } from '@typebot.io/env'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
@@ -49,9 +50,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
data: credentials,
})
const queryParams = stringify({ blockId, credentialsId })
- res.redirect(
- `${redirectUrl}?${queryParams}` ?? `${process.env.NEXTAUTH_URL}`
- )
+ res.redirect(`${redirectUrl}?${queryParams}` ?? `${env.NEXTAUTH_URL}`)
}
}
diff --git a/apps/builder/src/pages/api/customDomains/[domain].ts b/apps/builder/src/pages/api/customDomains/[domain].ts
index c94b191a986..c6480596dea 100644
--- a/apps/builder/src/pages/api/customDomains/[domain].ts
+++ b/apps/builder/src/pages/api/customDomains/[domain].ts
@@ -7,6 +7,7 @@ import {
} from '@typebot.io/lib/api'
import { got } from 'got'
import { getAuthenticatedUser } from '@/features/auth/helpers/getAuthenticatedUser'
+import { env } from '@typebot.io/env'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
@@ -31,8 +32,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const deleteDomainOnVercel = (name: string) =>
got.delete({
- url: `https://api.vercel.com/v8/projects/${process.env.NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME}/domains/${name}?teamId=${process.env.VERCEL_TEAM_ID}`,
- headers: { Authorization: `Bearer ${process.env.VERCEL_TOKEN}` },
+ url: `https://api.vercel.com/v8/projects/${env.NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME}/domains/${name}?teamId=${env.VERCEL_TEAM_ID}`,
+ headers: { Authorization: `Bearer ${env.VERCEL_TOKEN}` },
})
export default handler
diff --git a/apps/builder/src/pages/api/storage/upload-url.ts b/apps/builder/src/pages/api/storage/upload-url.ts
index 37a0eedeef7..b73fe1a4451 100644
--- a/apps/builder/src/pages/api/storage/upload-url.ts
+++ b/apps/builder/src/pages/api/storage/upload-url.ts
@@ -6,6 +6,7 @@ import {
methodNotAllowed,
notAuthenticated,
} from '@typebot.io/lib/api'
+import { env } from '@typebot.io/env'
const handler = async (
req: NextApiRequest,
@@ -16,11 +17,7 @@ const handler = async (
const user = await getAuthenticatedUser(req, res)
if (!user) return notAuthenticated(res)
- if (
- !process.env.S3_ENDPOINT ||
- !process.env.S3_ACCESS_KEY ||
- !process.env.S3_SECRET_KEY
- )
+ if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
return badRequest(
res,
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY'
diff --git a/apps/builder/src/pages/api/stripe/webhook.ts b/apps/builder/src/pages/api/stripe/webhook.ts
index 222bbf0c942..390afa8576b 100644
--- a/apps/builder/src/pages/api/stripe/webhook.ts
+++ b/apps/builder/src/pages/api/stripe/webhook.ts
@@ -8,10 +8,11 @@ import { Plan, WorkspaceRole } from '@typebot.io/prisma'
import { RequestHandler } from 'next/dist/server/next'
import { sendTelemetryEvents } from '@typebot.io/lib/telemetry/sendTelemetryEvent'
import { Settings } from '@typebot.io/schemas'
+import { env } from '@typebot.io/env'
-if (!process.env.STRIPE_SECRET_KEY || !process.env.STRIPE_WEBHOOK_SECRET)
+if (!env.STRIPE_SECRET_KEY || !env.STRIPE_WEBHOOK_SECRET)
throw new Error('STRIPE_SECRET_KEY or STRIPE_WEBHOOK_SECRET missing')
-const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
+const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15',
})
@@ -19,7 +20,7 @@ const cors = Cors({
allowMethods: ['POST', 'HEAD'],
})
-const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET as string
+const webhookSecret = env.STRIPE_WEBHOOK_SECRET as string
export const config = {
api: {
diff --git a/apps/builder/src/pages/api/typebots/[typebotId]/invitations.ts b/apps/builder/src/pages/api/typebots/[typebotId]/invitations.ts
index 0fd0101545f..c74ea9b4fde 100644
--- a/apps/builder/src/pages/api/typebots/[typebotId]/invitations.ts
+++ b/apps/builder/src/pages/api/typebots/[typebotId]/invitations.ts
@@ -13,8 +13,8 @@ import {
notAuthenticated,
} from '@typebot.io/lib/api'
import { getAuthenticatedUser } from '@/features/auth/helpers/getAuthenticatedUser'
-import { env } from '@typebot.io/lib'
import { sendGuestInvitationEmail } from '@typebot.io/emails'
+import { env } from '@typebot.io/env'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
@@ -80,11 +80,11 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
await prisma.invitation.create({
data: { email: email.toLowerCase().trim(), type, typebotId },
})
- if (env('E2E_TEST') !== 'true')
+ if (!env.NEXT_PUBLIC_E2E_TEST)
await sendGuestInvitationEmail({
to: email,
hostEmail: user.email ?? '',
- url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${typebot.workspaceId}`,
+ url: `${env.NEXTAUTH_URL}/typebots?workspaceId=${typebot.workspaceId}`,
guestEmail: email.toLowerCase(),
typebotName: typebot.name,
workspaceName: typebot.workspace?.name ?? '',
diff --git a/apps/builder/src/pages/api/workspaces/[workspaceId]/invitations.ts b/apps/builder/src/pages/api/workspaces/[workspaceId]/invitations.ts
index 016f85ded6b..4ffc058b665 100644
--- a/apps/builder/src/pages/api/workspaces/[workspaceId]/invitations.ts
+++ b/apps/builder/src/pages/api/workspaces/[workspaceId]/invitations.ts
@@ -8,8 +8,8 @@ import {
} from '@typebot.io/lib/api'
import { getAuthenticatedUser } from '@/features/auth/helpers/getAuthenticatedUser'
import { sendWorkspaceMemberInvitationEmail } from '@typebot.io/emails'
-import { env } from '@typebot.io/lib'
import { isSeatsLimitReached } from '@typebot.io/lib/pricing'
+import { env } from '@typebot.io/env'
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const user = await getAuthenticatedUser(req, res)
@@ -52,12 +52,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
userId: existingUser.id,
},
})
- if (env('E2E_TEST') !== 'true')
+ if (!env.NEXT_PUBLIC_E2E_TEST)
await sendWorkspaceMemberInvitationEmail({
to: data.email,
workspaceName: workspace.name,
guestEmail: data.email,
- url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspace.id}`,
+ url: `${env.NEXTAUTH_URL}/typebots?workspaceId=${workspace.id}`,
hostEmail: user.email ?? '',
})
return res.send({
@@ -71,12 +71,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
})
} else {
const invitation = await prisma.workspaceInvitation.create({ data })
- if (env('E2E_TEST') !== 'true')
+ if (!env.NEXT_PUBLIC_E2E_TEST)
await sendWorkspaceMemberInvitationEmail({
to: data.email,
workspaceName: workspace.name,
guestEmail: data.email,
- url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspace.id}`,
+ url: `${env.NEXTAUTH_URL}/typebots?workspaceId=${workspace.id}`,
hostEmail: user.email ?? '',
})
return res.send({ invitation })
diff --git a/apps/builder/src/pages/feedback.tsx b/apps/builder/src/pages/feedback.tsx
index 31e1566ebae..03c42581d31 100644
--- a/apps/builder/src/pages/feedback.tsx
+++ b/apps/builder/src/pages/feedback.tsx
@@ -4,6 +4,7 @@ import { isNotDefined } from '@typebot.io/lib'
import { sign } from 'jsonwebtoken'
import { getServerSession } from 'next-auth'
import { authOptions } from './api/auth/[...nextauth]'
+import { env } from '@typebot.io/env'
export default function Page() {
return null
@@ -28,7 +29,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}
const createSSOToken = (user: User) => {
- if (!process.env.SLEEKPLAN_SSO_KEY) return
+ if (!env.SLEEKPLAN_SSO_KEY) return
const userData = {
mail: user.email,
id: user.id,
@@ -36,5 +37,5 @@ const createSSOToken = (user: User) => {
img: user.image,
}
- return sign(userData, process.env.SLEEKPLAN_SSO_KEY, { algorithm: 'HS256' })
+ return sign(userData, env.SLEEKPLAN_SSO_KEY, { algorithm: 'HS256' })
}
diff --git a/apps/builder/src/pages/feedback/[feedbackId].ts b/apps/builder/src/pages/feedback/[feedbackId].ts
index 58b0ddca64f..8183e5469d7 100644
--- a/apps/builder/src/pages/feedback/[feedbackId].ts
+++ b/apps/builder/src/pages/feedback/[feedbackId].ts
@@ -4,6 +4,7 @@ import { isNotDefined } from '@typebot.io/lib'
import { sign } from 'jsonwebtoken'
import { authOptions } from '../api/auth/[...nextauth]'
import { GetServerSidePropsContext } from 'next'
+import { env } from '@typebot.io/env'
export default function Page() {
return null
@@ -29,7 +30,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
}
const createSSOToken = (user: User) => {
- if (!process.env.SLEEKPLAN_SSO_KEY) return
+ if (!env.SLEEKPLAN_SSO_KEY) return
const userData = {
mail: user.email,
id: user.id,
@@ -37,5 +38,5 @@ const createSSOToken = (user: User) => {
img: user.image,
}
- return sign(userData, process.env.SLEEKPLAN_SSO_KEY, { algorithm: 'HS256' })
+ return sign(userData, env.SLEEKPLAN_SSO_KEY, { algorithm: 'HS256' })
}
diff --git a/apps/builder/src/test/utils/databaseActions.ts b/apps/builder/src/test/utils/databaseActions.ts
index 49772024218..bf642c69716 100644
--- a/apps/builder/src/test/utils/databaseActions.ts
+++ b/apps/builder/src/test/utils/databaseActions.ts
@@ -7,10 +7,11 @@ import {
} from '@typebot.io/prisma'
import Stripe from 'stripe'
import { proWorkspaceId } from '@typebot.io/lib/playwright/databaseSetup'
+import { env } from '@typebot.io/env'
const prisma = new PrismaClient()
-const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '', {
+const stripe = new Stripe(env.STRIPE_SECRET_KEY ?? '', {
apiVersion: '2022-11-15',
})
diff --git a/apps/docs/docs/self-hosting/cloudron.mdx b/apps/docs/docs/self-hosting/cloudron.mdx
deleted file mode 100644
index a3b3a47a760..00000000000
--- a/apps/docs/docs/self-hosting/cloudron.mdx
+++ /dev/null
@@ -1,64 +0,0 @@
----
-sidebar_position: 3
----
-
-import { SponsorButton } from '../../src/js/SponsorButton.jsx'
-
-# Cloudron
-
-:::note
-The easiest way to get started with Typebot is with [the official managed service in the Cloud](https://app.typebot.io). You'll have high availability, backups, security, and maintenance all managed for you by me, Baptiste, Typebot's founder.
-
-The cloud version can save a substantial amount of developer time and resources. For most sites this ends up being the best value option and the revenue goes to funding the maintenance and further development of Typebot. So you’ll be supporting open source software and getting a great service!
-:::
-
-## Requirements
-
-You need a server with [Cloudron](https://www.cloudron.io/) installed and a machine with the [Cloudron CLI](https://docs.cloudron.io/packaging/cli/) installed.
-
-## Installation
-
-### 1. Download the compose file
-
-On the machine that has the `cloudron` CLI, download the latest `CloudronManifest.json` file:
-
-```sh
- wget https://github.com/raw/baptisteArno/typebot.io/latest/packages/cloudron/CloudronManifest.json
-```
-
-### 2. Install the app
-
-Install the app:
-
-```sh
-cloudron install --image baptistearno/typebot-cloudron:latest
-```
-
-## Configuration
-
-You can further configure the app by opening the app File Manager in Cloudron and edit the `env.sh` file.
-
-There, you can add any environment variable you want, like:
-
-```sh
-export GITHUB_CLIENT_ID="your_github_client_id"
-export GITHUB_CLIENT_SECRET="your_github_client_secret"
-```
-
-Then restart the app to apply the changes.
-
-## Update
-
-To update the app, run:
-
-```sh
-cloudron update --app the_name_of_your_app --image baptistearno/typebot-cloudron:latest
-```
-
-:::note
-If you're self-hosting Typebot, [sponsoring me](https://github.com/sponsors/baptisteArno) is a great way to give back to the community and to contribute to the long-term sustainability of the project.
-
-
-
-Thank you for supporting independent creators of Free Open Source Software!
-:::
diff --git a/apps/docs/docs/self-hosting/configuration/builder.mdx b/apps/docs/docs/self-hosting/configuration.md
similarity index 97%
rename from apps/docs/docs/self-hosting/configuration/builder.mdx
rename to apps/docs/docs/self-hosting/configuration.md
index 528789aa9ee..4eb933e5c07 100644
--- a/apps/docs/docs/self-hosting/configuration/builder.mdx
+++ b/apps/docs/docs/self-hosting/configuration.md
@@ -1,11 +1,11 @@
---
-title: Builder
+sidebar_position: 2
---
-import { SponsorButton } from '../../../src/js/SponsorButton.jsx'
-import { Asterix } from '../../../src/js/Asterix.jsx'
+import { SponsorButton } from '../../src/js/SponsorButton.jsx'
+import { Asterix } from '../../src/js/Asterix.jsx'
-# Builder configuration
+# Configuration
Parameters marked with are required.
@@ -22,6 +22,7 @@ Parameters marked with are required.
| DEFAULT_WORKSPACE_PLAN | FREE | Default workspace plan on user creation or when a user creates a new workspace. Possible values are `FREE`, `STARTER`, `PRO`, `LIFETIME`, `UNLIMITED`. The default plan for admin user is `UNLIMITED` |
| DISABLE_SIGNUP | false | Disable new user sign ups. Invited users are still able to sign up. |
| NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID | | Typebot ID used for the onboarding. Onboarding page is skipped if not provided. |
+| DEBUG | false | If enabled, the server will print valuable logs to debug config issues. |
## Email (Auth, notifications)
diff --git a/apps/docs/docs/self-hosting/configuration/_category_.json b/apps/docs/docs/self-hosting/configuration/_category_.json
deleted file mode 100644
index d60b9dce6e6..00000000000
--- a/apps/docs/docs/self-hosting/configuration/_category_.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "label": "Configuration",
- "position": 2
-}
diff --git a/apps/docs/docs/self-hosting/configuration/overview.md b/apps/docs/docs/self-hosting/configuration/overview.md
deleted file mode 100644
index bb4994c91fc..00000000000
--- a/apps/docs/docs/self-hosting/configuration/overview.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-sidebar_position: 1
-title: Overview
-slug: /self-hosting/configuration
----
-
-# Configuration
-
-:::note
-The easiest way to get started with Typebot is with [the official managed service in the Cloud](https://app.typebot.io). You'll have high availability, backups, security, and maintenance all managed for you by me, Baptiste, Typebot's founder.
-
-The cloud version can save a substantial amount of developer time and resources. For most sites this ends up being the best value option and the revenue goes to funding the maintenance and further development of Typebot. So you’ll be supporting open source software and getting a great service!
-:::
-
-When running Typebot on your machine, the following configuration parameters can be supplied as environment variables.
-
-Typebot is composed of 2 main applications:
-
-- The builder, where you build your typebots
-- The viewer, where your user answer the typebot
-
-Both apps have their environment to configure properly:
-
-- [Builder configuration](/self-hosting/configuration/builder)
-- [Viewer configuration](/self-hosting/configuration/viewer)
diff --git a/apps/docs/docs/self-hosting/configuration/viewer.mdx b/apps/docs/docs/self-hosting/configuration/viewer.mdx
deleted file mode 100644
index 82982553a5e..00000000000
--- a/apps/docs/docs/self-hosting/configuration/viewer.mdx
+++ /dev/null
@@ -1,105 +0,0 @@
----
-title: Viewer
----
-
-import { SponsorButton } from '../../../src/js/SponsorButton.jsx'
-import { Asterix } from '../../../src/js/Asterix.jsx'
-
-# Viewer configuration
-
-Parameters marked with are required.
-
-## General
-
-| Parameter | Default | Description |
-| --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| DATABASE_URL | | The database URL |
-| ENCRYPTION_SECRET | | A 256-bit key used to encrypt sensitive data. It is strongly recommended to [generate](https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx) a new one. The secret should be the same between builder and viewer. |
-| NEXT_PUBLIC_VIEWER_URL | | The viewer base URL. Should be the publicly accessible URL (i.e. `https://bot.domain.com`) |
-| NEXTAUTH_URL | | The builder base URL. Should be the publicly accessible URL (i.e. `https://typebot.domain.com`) |
-| DEBUG | false | If enabled, the server will print valuable logs to debug config issues. |
-
-## Emails (Notifications)
-
-Used for sending email notifications and authentication
-
-| Parameter | Default | Description |
-| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| SMTP_USERNAME | | SMTP username |
-| SMTP_PASSWORD | | SMTP password |
-| SMTP_HOST | | SMTP host. (i.e. `smtp.host.com`) |
-| SMTP_PORT | 25 | SMTP port |
-| SMTP_FROM | | From name and email (i.e. `'Typebot Notifications' `) |
-| SMTP_SECURE | false | If true the connection will use TLS when connecting to server. If false (the default) then TLS is used if server supports the STARTTLS extension. In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false |
-
-## Google (Sheets)
-
-Used when executing a Google Sheets block. Make sure to set the required scopes (`userinfo.email`, `spreadsheets`, `drive.readonly`) in your console
-
-| Parameter | Default | Description |
-| -------------------- | ------- | --------------------------------------------- |
-| GOOGLE_CLIENT_ID | | The Client ID from the Google API Console |
-| GOOGLE_CLIENT_SECRET | | The Client secret from the Google API Console |
-
-### Configuration
-
-https://console.developers.google.com/apis/credentials
-
-The "Authorized redirect URIs" used when creating the credentials must include your full domain and end in the callback path:
-
-- For production: https://{YOUR_DOMAIN}/api/credentials/google-sheets/callback
-- For development: http://localhost:3000/api/credentials/google-sheets/callback
-
-## S3 Storage (File upload input)
-
-Used for the file upload input. It can be any S3 compatible object storage service (Minio, Digital Oceans Space, AWS S3...)
-
-| Parameter | Default | Description |
-| ------------- | ------- | -------------------------------------------------------------- |
-| S3_ACCESS_KEY | | S3 access key. Also used to check if upload feature is enabled |
-| S3_SECRET_KEY | | S3 secret key. |
-| S3_BUCKET | typebot | Name of the bucket where assets will be uploaded in. |
-| S3_PORT | | S3 Host port number |
-| S3_ENDPOINT | | S3 endpoint (i.e. `s3.domain.com`). |
-| S3_SSL | true | Use SSL when establishing the connection. |
-| S3_REGION | | S3 region. |
-
-Note that for AWS S3, your endpoint is usually: `s3..amazonaws.com`
-
-Your bucket must have the following policy that tells S3 to allow public read when an object is located under the public folder:
-
-```json
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Sid": "PublicRead",
- "Effect": "Allow",
- "Principal": "*",
- "Action": "s3:GetObject",
- "Resource": "arn:aws:s3:::/public/*"
- }
- ]
-}
-```
-
-You also need to configure CORS so that an object can be uploaded from the browser:
-
-```json
-[
- {
- "AllowedHeaders": ["*"],
- "AllowedMethods": ["PUT", "POST"],
- "AllowedOrigins": ["*"],
- "ExposeHeaders": ["ETag"]
- }
-]
-```
-
-:::note
-If you're self-hosting Typebot, [sponsoring me](https://github.com/sponsors/baptisteArno) is a great way to give back to the community and to contribute to the long-term sustainability of the project.
-
-
-
-Thank you for supporting independent creators of Free Open Source Software!
-:::
diff --git a/apps/docs/docs/self-hosting/get-started.md b/apps/docs/docs/self-hosting/get-started.md
index 3cdc52126b7..dbbba2c3ec6 100644
--- a/apps/docs/docs/self-hosting/get-started.md
+++ b/apps/docs/docs/self-hosting/get-started.md
@@ -73,6 +73,6 @@ Typebot is composed of 2 Next.js applications you need to deploy:
I've written guides on how to deploy Typebot using:
-- [Docker](/self-hosting/docker)
-- [Vercel](/self-hosting/vercel)
-- [Manual](/self-hosting/manual)
+- [Docker](/self-hosting/guides/docker)
+- [Vercel](/self-hosting/guides/vercel)
+- [Manual](/self-hosting/guides/manual)
diff --git a/apps/docs/docs/self-hosting/guides/_category_.json b/apps/docs/docs/self-hosting/guides/_category_.json
new file mode 100644
index 00000000000..c59a630d3b4
--- /dev/null
+++ b/apps/docs/docs/self-hosting/guides/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "Guides",
+ "position": 3
+}
diff --git a/apps/docs/docs/self-hosting/docker.mdx b/apps/docs/docs/self-hosting/guides/docker.mdx
similarity index 73%
rename from apps/docs/docs/self-hosting/docker.mdx
rename to apps/docs/docs/self-hosting/guides/docker.mdx
index eec46162fd0..f4395bcbad8 100644
--- a/apps/docs/docs/self-hosting/docker.mdx
+++ b/apps/docs/docs/self-hosting/guides/docker.mdx
@@ -1,8 +1,8 @@
---
-sidebar_position: 2
+sidebar_position: 3
---
-import { SponsorButton } from '../../src/js/SponsorButton.jsx'
+import { SponsorButton } from '../../../src/js/SponsorButton.jsx'
# Docker
@@ -20,27 +20,23 @@ You need a server with Docker installed. If your server doesn't come with Docker
### 1. Download the compose file
-On your server, download the latest `docker-compose.yml` file:
+On your server, download the latest `docker-compose.yml` and the starter `.env` file:
```sh
wget https://github.com/raw/baptisteArno/typebot.io/latest/docker-compose.yml
+ wget https://github.com/raw/baptisteArno/typebot.io/latest/.env.example -O .env
```
### 2. Add the required configuration
-The compose file has placeholders for the required parameters. To set the parameters you'll first need a random 32-character secret key which will be used to encrypt sensitive data. Here is a simple way to generate one:
+1. You'll first need a random 32-character secret key which will be used to encrypt sensitive data. Here is a simple way to generate one:
-```sh
-openssl rand -base64 24 | tr -d '\n' ; echo
-```
+ ```sh
+ openssl rand -base64 24 | tr -d '\n' ; echo
+ ```
-Now edit `docker-compose.yml` and:
-
-- Replace `` with the generated secret.
-- Replace `` with the public URL of the builder (i.e. `https://typebot.domain.com:8080`).
-- Replace `` with the public URL of the viewer (i.e. `https://typebot.domain.com:8081`).
-- Replace `` with the email address of the administrator.
-- Configure at least one authentication provider (Email, Google, GitHub, Facebook or GitLab). More info here: [Configuration](https://docs.typebot.io/self-hosting/configuration).
+2. Fill the `.env` file with your values.
+3. Configure at least one authentication provider (Email, Google, GitHub, Facebook or GitLab). More info here: [Configuration](https://docs.typebot.io/self-hosting/configuration).
By default the compose file will pull the latest stable Typebot images: `baptistearno/typebot-builder:latest` and `baptistearno/typebot-viewer:latest`. You can decide to replace `latest` with a specific version or with `main` to get the latest modifications. You can find all the existing tags [here](https://hub.docker.com/r/baptistearno/typebot-builder/tags)
@@ -52,12 +48,13 @@ Once you've added your configuration to the compose file, you're ready to start
docker-compose up -d
```
-When you run this command it does the following:
+When you run this command, by default, it does the following:
- Create a database
- Run the migrations
- Start the builder on port 8080
- Start the viewer on port 8081
+- All Typebot's data is stored in the `.typebot` folder in the current directory
You can now navigate to `http://typebot.domain.com:8080` and see the login screen. Login with the admin email to have access to a Team plan workspace automatically.
@@ -67,14 +64,33 @@ Typebot server itself does not perform SSL termination. It only runs on unencryp
Typebot is updated regularly, but it is up to you to apply these updates on your server. By virtue of using Docker, these updates are safe and easy to apply.
-```sh
-docker-compose down --remove-orphans
-docker-compose pull typebot-builder
-docker-compose pull typebot-viewer
-docker-compose up -d
-```
+1. Pull the new images:
+
+ ```sh
+ docker-compose pull typebot-builder
+ docker-compose pull typebot-viewer
+ ```
+
+ Alternatively, you can pull specific versions:
-The self-hosted version is somewhat of a LTS, only getting the changes after they have been battle tested on the hosted version. If you want features as soon as they are available, consider becoming a hosted customer.
+ ```sh
+ docker-compose pull typebot-builder:1.0.0
+ docker-compose pull typebot-viewer:1.0.0
+ ```
+
+2. Stop the server:
+
+ ```sh
+ docker-compose down
+ ```
+
+3. Start the server (with the new images):
+
+ ```sh
+ docker-compose up -d
+ ```
+
+The self-hosted version is somewhat of a LTS, only getting the changes (~ once per month) after they have been battle tested on the cloud version. If you want features as soon as they are available, consider becoming a [cloud user](https://app.typebot.io).
## Optional extras
@@ -99,7 +115,7 @@ services:
restart: always
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- - caddy-certificates:/data/caddy
+ - {$PWD}/.typebot/caddy-certificates:/data/caddy
ports:
- '80:80'
- '443:443'
@@ -118,10 +134,6 @@ services:
virtual.host: 'bot.domain.com' # change to your domain name
virtual.port: '3000'
virtual.tls-email: 'admin@example.com' # change to your email
-
-volumes:
- caddy-certificates:
- driver: local
```
This config requires you to add the following DNS entry:
@@ -147,7 +159,7 @@ If you're already running a reverse proxy, the most important things to note are
### SMTP
-I highly recommend using an external SMTP service. There are tons of options out there, including [SendInBlue](https://www.sendinblue.com/), [Mailgun](https://www.mailgun.com/) and [SendGrid](https://sendgrid.com/). It will avoid severe headaches 😅. Then, you will only need to add the required [SMTP configuration variables](/self-hosting/configuration/builder#email-auth-notifications).
+I highly recommend using an external SMTP service. There are tons of options out there, including [SendInBlue](https://www.sendinblue.com/), [Mailgun](https://www.mailgun.com/) and [SendGrid](https://sendgrid.com/). It will avoid severe headaches 😅. Then, you will only need to add the required [SMTP configuration variables](/self-hosting/configuration#email-auth-notifications).
If, however, you don't want to, you can instantiate an SMTP server in the docker-compose file.
@@ -157,13 +169,13 @@ services:
mail:
image: bytemark/smtp
restart: always
- typebot-builder:
- environment:
- - SMTP_HOST=mail
- - NEXT_PUBLIC_SMTP_FROM=notifications@typebot.domain.com # change to your domain name
- typebot-viewer:
- - SMTP_HOST=mail
- - NEXT_PUBLIC_SMTP_FROM=notifications@typebot.domain.com # change to your domain name
+```
+
+And add the following variables to your `.env` file:
+
+```
+SMTP_HOST=mail
+NEXT_PUBLIC_SMTP_FROM=notifications@typebot.domain.com
```
You will probably need to make sure that `typebot.domain.com` has a valid SPF record and that your server IP has a rDNS set up.
@@ -186,7 +198,7 @@ services:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio123
volumes:
- - s3_data:/data
+ - ${PWD}/.typebot/s3:/data
# This service just makes sure a bucket with the right policies is created
createbuckets:
image: minio/mc
@@ -200,21 +212,15 @@ services:
/usr/bin/mc anonymous set public minio/typebot/public;
exit 0;
"
- typebot-builder:
- environment:
- - S3_ACCESS_KEY=minio
- - S3_SECRET_KEY=minio123
- - S3_BUCKET=typebot
- - S3_ENDPOINT=storage.domain.com # change to your domain name
- typebot-viewer:
- environment:
- - S3_ACCESS_KEY=minio
- - S3_SECRET_KEY=minio123
- - S3_BUCKET=typebot
- - S3_ENDPOINT=storage.domain.com # change to your domain name
+```
+
+And add the following variables to your `.env` file:
-volumes:
- s3_data:
+```
+S3_ACCESS_KEY=minio
+S3_SECRET_KEY=minio123
+S3_BUCKET=typebot
+S3_ENDPOINT=storage.domain.com
```
This config requires you to add the following DNS entry:
@@ -237,7 +243,7 @@ services:
restart: always
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- - caddy-certificates:/data/caddy
+ - {$PWD}/.typebot/caddy-certificates:/data/caddy
ports:
- '80:80'
- '443:443'
@@ -248,7 +254,7 @@ services:
image: postgres:13
restart: always
volumes:
- - db_data:/var/lib/postgresql/data
+ - {$PWD}/.typebot/database:/var/lib/postgresql/data
environment:
- POSTGRES_DB=typebot
- POSTGRES_PASSWORD=typebot
@@ -264,18 +270,8 @@ services:
extra_hosts:
- 'host.docker.internal:host-gateway'
# See https://docs.typebot.io/self-hosting/configuration for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXTAUTH_URL=https://typebot.domain.com
- - NEXT_PUBLIC_VIEWER_URL=https://bot.domain.com
- - ENCRYPTION_SECRET=K+Bar660Ofaec7v1jHC25tAn3l2b7c81
- - ADMIN_EMAIL=baptiste.arnaud95@gmail.com
- - SMTP_HOST=mail
- - NEXT_PUBLIC_SMTP_FROM=notifications@typebot.domain.com
- - S3_ACCESS_KEY=minio
- - S3_SECRET_KEY=minio123
- - S3_BUCKET=typebot
- - S3_ENDPOINT=storage.domain.com
+ env_file:
+ - .env
typebot-viewer:
labels:
virtual.host: 'bot.domain.com' # change to your domain
@@ -284,16 +280,8 @@ services:
image: baptistearno/typebot-viewer:latest
restart: always
# See https://docs.typebot.io/self-hosting/configuration for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXT_PUBLIC_VIEWER_URL=https://bot.domain.com
- - ENCRYPTION_SECRET=K+Bar660Ofaec7v1jHC25tAn3l2b7c81
- - SMTP_HOST=mail
- - NEXT_PUBLIC_SMTP_FROM=notifications@typebot.domain.com
- - S3_ACCESS_KEY=minio
- - S3_SECRET_KEY=minio123
- - S3_BUCKET=typebot
- - S3_ENDPOINT=storage.domain.com
+ env_file:
+ - .env
mail:
image: bytemark/smtp
restart: always
@@ -310,7 +298,7 @@ services:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio123
volumes:
- - s3_data:/data
+ - {$PWD}/.typebot/s3:/data
# This service just make sure a bucket with the right policies is created
createbuckets:
image: minio/mc
@@ -324,11 +312,6 @@ services:
/usr/bin/mc anonymous set public minio/typebot/public;
exit 0;
"
-volumes:
- db_data:
- s3_data:
- caddy-certificates:
- driver: local
```
:::note
diff --git a/apps/docs/docs/self-hosting/manual.md b/apps/docs/docs/self-hosting/guides/manual.md
similarity index 91%
rename from apps/docs/docs/self-hosting/manual.md
rename to apps/docs/docs/self-hosting/guides/manual.md
index 054a0fc4598..0d75965f59c 100644
--- a/apps/docs/docs/self-hosting/manual.md
+++ b/apps/docs/docs/self-hosting/guides/manual.md
@@ -18,22 +18,18 @@ The cloud version can save a substantial amount of developer time and resources.
## Getting Started
-1. Fork/clone the repository
+1. Fork/clone the repository and checkout the latest stable version.
```sh
git clone git@github.com:/typebot.io.git
+cd typebot.io
+git checkout latest
```
2. Setup environment variables by copying the example files and following the [configuration guide](/self-hosting/configuration) to fill in the missing values.
```sh
-cd typebot.io
-# check out the latest stable version or the one you want to use
-git checkout latest
-# copy the example env file
-cp packages/prisma/.env.example packages/prisma/.env
-cp apps/builder/.env.local.example apps/builder/.env.local
-cp apps/viewer/.env.local.example apps/viewer/.env.local
+cp .env.example .env
```
:::note
@@ -50,9 +46,6 @@ pnpm install
```sh
pnpm run build:apps
-# or build them separately
-pnpm run build:builder
-pnpm run build:viewer
```
:::note
diff --git a/apps/docs/docs/self-hosting/planetscale.md b/apps/docs/docs/self-hosting/guides/planetscale.md
similarity index 74%
rename from apps/docs/docs/self-hosting/planetscale.md
rename to apps/docs/docs/self-hosting/guides/planetscale.md
index 65e27bcfe83..2968ea2afe1 100644
--- a/apps/docs/docs/self-hosting/planetscale.md
+++ b/apps/docs/docs/self-hosting/guides/planetscale.md
@@ -1,10 +1,10 @@
# Using a Planetscale database
-Typebot is also pluggable to a Planetscale database. But it means, you'll need to push schema changes manually, yourself.
+Typebot is also pluggable to a Planetscale database. But it means, you'll need to push schema changes manually.
To do so, follow these instructions:
-1. Copy `packages/prisma/.env.example` to `packages/prisma/.env` and replace `DATABASE_URL` with a development branch
+1. Replace `DATABASE_URL` with a Planetscale development branch URL.
2. From the `packages/prisma` directory, run a the db push command: `pnpm run db:push`
3. Then, in Planetscale dashboard, or using their CLI, you can create a new deploy request from this development branch to your production branch.
diff --git a/apps/docs/docs/self-hosting/vercel.md b/apps/docs/docs/self-hosting/guides/vercel.md
similarity index 90%
rename from apps/docs/docs/self-hosting/vercel.md
rename to apps/docs/docs/self-hosting/guides/vercel.md
index a2b7694cdae..a643b04c2fc 100644
--- a/apps/docs/docs/self-hosting/vercel.md
+++ b/apps/docs/docs/self-hosting/guides/vercel.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 2
+sidebar_position: 4
---
# Vercel
@@ -27,7 +27,7 @@ Fork the repository
5. Change the build command to:
```sh
- cd ../.. && pnpm build:builder && pnpm db:migrate
+ cd ../.. && pnpm turbo build --filter=builder... && pnpm db:migrate
```
6. Add the required environment variables ([Check out the configuration guide](/self-hosting/configuration))
@@ -42,7 +42,7 @@ Fork the repository
5. Change the build command to:
```sh
- cd ../.. && pnpm build:viewer && pnpm db:migrate
+ cd ../.. && pnpm pnpm turbo build --filter=viewer... && pnpm db:migrate
```
6. Add the required environment variables ([Check out the configuration guide](/self-hosting/configuration))
diff --git a/apps/docs/docs/self-hosting/troubleshoot.md b/apps/docs/docs/self-hosting/troubleshoot.md
index ef63ccc85d6..6059e2045a8 100644
--- a/apps/docs/docs/self-hosting/troubleshoot.md
+++ b/apps/docs/docs/self-hosting/troubleshoot.md
@@ -6,4 +6,4 @@ You most likely forgot to set up an `ADMIN_EMAIL` variable or did not signed up
## I can't upload files
-You need to add an [S3 configuration](./configuration/builder#s3-storage-media-uploads) to your project. If you are self-hosting with Docker, you can [add a S3 service to your docker-compose file](./docker#s3-storage).
+You need to add an [S3 configuration](./configuration#s3-storage-media-uploads) to your project. If you are self-hosting with Docker, you can [add a S3 service to your docker-compose file](./guides/docker#s3-storage).
diff --git a/apps/docs/openapi/builder/_spec_.json b/apps/docs/openapi/builder/_spec_.json
index f3005d6996e..ed5675b2429 100644
--- a/apps/docs/openapi/builder/_spec_.json
+++ b/apps/docs/openapi/builder/_spec_.json
@@ -2559,8 +2559,7 @@
"required": [
"id"
],
- "additionalProperties": false,
- "description": "Deprecated. Use `filter` instead."
+ "additionalProperties": false
}
}
},
@@ -2606,8 +2605,7 @@
"required": [
"id"
],
- "additionalProperties": false,
- "description": "Deprecated. Use `filter` instead."
+ "additionalProperties": false
}
},
"referenceCell": {
diff --git a/apps/docs/openapi/chat/_spec_.json b/apps/docs/openapi/chat/_spec_.json
index 82ede514f77..3a62c168276 100644
--- a/apps/docs/openapi/chat/_spec_.json
+++ b/apps/docs/openapi/chat/_spec_.json
@@ -2136,8 +2136,7 @@
"required": [
"id"
],
- "additionalProperties": false,
- "description": "Deprecated. Use `filter` instead."
+ "additionalProperties": false
}
}
},
@@ -2183,8 +2182,7 @@
"required": [
"id"
],
- "additionalProperties": false,
- "description": "Deprecated. Use `filter` instead."
+ "additionalProperties": false
}
},
"referenceCell": {
diff --git a/apps/docs/package.json b/apps/docs/package.json
index e88ead0f0e9..cce0c35cffd 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -13,7 +13,7 @@
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper",
- "api:generate": "tsx --tsconfig ../builder/tsconfig.json ../builder/src/helpers/server/generateOpenApi.ts && tsx --tsconfig ../viewer/openapi.tsconfig.json ../viewer/src/helpers/server/generateOpenApi.ts"
+ "api:generate": "dotenv -e ./.env -e ../../.env -- tsx --tsconfig ../builder/tsconfig.json ../builder/src/helpers/server/generateOpenApi.ts && dotenv -e ./.env -e ../../.env -- tsx --tsconfig ../viewer/openapi.tsconfig.json ../viewer/src/helpers/server/generateOpenApi.ts"
},
"dependencies": {
"@docusaurus/core": "2.4.1",
@@ -46,6 +46,7 @@
"@algolia/client-search": "4.15.0",
"@docusaurus/types": "^2.3.1",
"@types/react": "18.0.28",
+ "dotenv-cli": "^7.2.1",
"tsx": "3.12.5",
"typescript": "4.9.5",
"webpack": "5.76.1"
diff --git a/apps/docs/vercel.json b/apps/docs/vercel.json
new file mode 100644
index 00000000000..558ddaeadf9
--- /dev/null
+++ b/apps/docs/vercel.json
@@ -0,0 +1,12 @@
+{
+ "rewrites": [
+ {
+ "source": "/self-hosting/configuration",
+ "destination": "/self-hosting/configuration"
+ },
+ {
+ "source": "/self-hosting/configuration/:path*",
+ "destination": "/self-hosting/configuration"
+ }
+ ]
+}
diff --git a/apps/landing-page/.env.docker b/apps/landing-page/.env.docker
deleted file mode 100644
index 22e558f5abd..00000000000
--- a/apps/landing-page/.env.docker
+++ /dev/null
@@ -1,2 +0,0 @@
-# Don't edit this file
-NEXT_PUBLIC_VIEWER_URL=
diff --git a/apps/landing-page/.env.local.example b/apps/landing-page/.env.local.example
deleted file mode 100644
index 9b67d9b54a9..00000000000
--- a/apps/landing-page/.env.local.example
+++ /dev/null
@@ -1,2 +0,0 @@
-NEXT_PUBLIC_VIEWER_URL=http://localhost:3001
-LANDING_PAGE_HOST=http://localhost:3002
\ No newline at end of file
diff --git a/apps/landing-page/package.json b/apps/landing-page/package.json
index 8f0f593b2c5..815a1ff056e 100644
--- a/apps/landing-page/package.json
+++ b/apps/landing-page/package.json
@@ -2,10 +2,9 @@
"name": "landing-page",
"version": "1.0.0",
"scripts": {
- "dev": "cross-env ENVSH_ENV=.env.local bash ../../scripts/inject-runtime-env.sh next dev -p 3002",
- "start": "next start",
- "build": "next build",
- "build:env": "cd ../.. && cross-env ENVSH_ENV=./apps/landing-page/.env.docker ENVSH_OUTPUT=./apps/landing-page/public/__env.js bash scripts/inject-runtime-env.sh",
+ "dev": "dotenv -e ./.env -e ../../.env -- next dev -p 3002",
+ "start": "dotenv -e ./.env -e ../../.env -- next start",
+ "build": "dotenv -e ./.env -e ../../.env -- next build",
"lint": "next lint",
"analyze": "cross-env ANALYZE=true next build"
},
@@ -14,33 +13,33 @@
"@chakra-ui/react": "2.7.1",
"@emotion/react": "11.11.1",
"@emotion/styled": "11.11.0",
- "@vercel/analytics": "1.0.1",
+ "@typebot.io/lib": "workspace:*",
"@typebot.io/nextjs": "workspace:*",
- "aos": "2.3.4",
"@typebot.io/prisma": "workspace:*",
+ "@typebot.io/schemas": "workspace:*",
+ "aos": "2.3.4",
"focus-visible": "5.2.0",
"framer-motion": "10.12.20",
- "@typebot.io/schemas": "workspace:*",
"next": "13.4.3",
"react": "18.2.0",
- "react-dom": "18.2.0",
- "@typebot.io/lib": "workspace:*"
+ "react-dom": "18.2.0"
},
"devDependencies": {
"@babel/core": "7.22.9",
"@chakra-ui/styled-system": "2.9.1",
"@next/bundle-analyzer": "13.4.9",
+ "@typebot.io/tsconfig": "workspace:*",
"@types/aos": "3.0.4",
"@types/node": "20.4.2",
"@types/react": "18.2.15",
"autoprefixer": "10.4.14",
"cross-env": "7.0.3",
+ "dotenv-cli": "^7.2.1",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
"next-transpile-modules": "10.0.0",
"postcss": "8.4.26",
"prettier": "3.0.0",
- "@typebot.io/tsconfig": "workspace:*",
"typescript": "5.1.6"
}
}
diff --git a/apps/landing-page/pages/_document.tsx b/apps/landing-page/pages/_document.tsx
index 62348ef94a7..1dabc22bbb0 100644
--- a/apps/landing-page/pages/_document.tsx
+++ b/apps/landing-page/pages/_document.tsx
@@ -20,8 +20,6 @@ class MyDocument extends Document {
{/* eslint-disable-next-line @next/next/no-css-tags */}
- {/* eslint-disable-next-line @next/next/no-sync-scripts */}
-
diff --git a/apps/viewer/.env.docker b/apps/viewer/.env.docker
deleted file mode 100644
index 4e173dc8461..00000000000
--- a/apps/viewer/.env.docker
+++ /dev/null
@@ -1,3 +0,0 @@
-# Don't edit this file
-NEXT_PUBLIC_VIEWER_URL=
-NEXT_PUBLIC_E2E_TEST=
diff --git a/apps/viewer/.env.local.example b/apps/viewer/.env.local.example
deleted file mode 100644
index 5c2ed747dc5..00000000000
--- a/apps/viewer/.env.local.example
+++ /dev/null
@@ -1,15 +0,0 @@
-# Make sure to change this to your own random string of 32 characters (https://docs.typebot.io/self-hosting/docker#2-add-the-required-configuration)
-ENCRYPTION_SECRET=H+KbL/OFrqbEuDy/1zX8bsPG+spXri3S
-NEXT_PUBLIC_VIEWER_URL=http://localhost:3001
-DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
-NEXTAUTH_URL=http://localhost:3000
-
-S3_ACCESS_KEY=minio
-S3_SECRET_KEY=minio123
-S3_BUCKET=typebot
-S3_PORT=9000
-S3_ENDPOINT=localhost
-S3_SSL=false
-
-# For more configuration options check out:
-# https://docs.typebot.io/self-hosting/configuration
diff --git a/apps/viewer/.eslintignore b/apps/viewer/.eslintignore
deleted file mode 100644
index 4b831b41542..00000000000
--- a/apps/viewer/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-next.config.js
\ No newline at end of file
diff --git a/apps/viewer/next.config.js b/apps/viewer/next.config.mjs
similarity index 90%
rename from apps/viewer/next.config.js
rename to apps/viewer/next.config.mjs
index da818474732..8345aae2884 100644
--- a/apps/viewer/next.config.js
+++ b/apps/viewer/next.config.mjs
@@ -1,5 +1,14 @@
-const { withSentryConfig } = require('@sentry/nextjs')
-const path = require('path')
+import { withSentryConfig } from '@sentry/nextjs'
+import { join, dirname } from 'path'
+import '@typebot.io/env/dist/env.mjs'
+import { fileURLToPath } from 'url'
+import { configureRuntimeEnv } from 'next-runtime-env/build/configure.js'
+
+const __filename = fileURLToPath(import.meta.url)
+
+const __dirname = dirname(__filename)
+
+configureRuntimeEnv()
const landingPagePaths = [
'/',
@@ -20,7 +29,7 @@ const nextConfig = {
],
output: 'standalone',
experimental: {
- outputFileTracingRoot: path.join(__dirname, '../../'),
+ outputFileTracingRoot: join(__dirname, '../../'),
},
async rewrites() {
return {
@@ -130,7 +139,7 @@ const sentryWebpackPluginOptions = {
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer',
}
-module.exports = process.env.NEXT_PUBLIC_SENTRY_DSN
+export default process.env.NEXT_PUBLIC_SENTRY_DSN
? withSentryConfig(
{
...nextConfig,
diff --git a/apps/viewer/package.json b/apps/viewer/package.json
index 2bbc7c701f1..0dd106999bf 100644
--- a/apps/viewer/package.json
+++ b/apps/viewer/package.json
@@ -3,22 +3,20 @@
"license": "AGPL-3.0-or-later",
"version": "0.1.0",
"scripts": {
- "dev": "cross-env ENVSH_ENV=.env.local bash ../../scripts/inject-runtime-env.sh next dev -p 3001",
- "build": "cross-env ENVSH_ENV=.env.local bash ../../scripts/inject-runtime-env.sh next build",
- "build:docker": "next build",
- "build:env": "cd ../.. && cross-env ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash scripts/inject-runtime-env.sh",
- "start": "next start -p 3001",
- "lint": "next lint",
- "test": "pnpm playwright test",
+ "dev": "dotenv -e ./.env -e ../../.env -- next dev -p 3001",
+ "build": "dotenv -e ./.env -e ../../.env -- next build",
+ "start": "dotenv -e ./.env -e ../../.env -- next start",
+ "lint": "dotenv -e ./.env -e ../../.env -- next lint",
+ "test": "dotenv -e ./.env -e ../../.env -- pnpm playwright test",
"test:report": "pnpm playwright show-report"
},
"dependencies": {
"@planetscale/database": "^1.8.0",
"@sentry/nextjs": "7.58.1",
"@trpc/server": "10.34.0",
- "@typebot.io/prisma": "workspace:*",
"@typebot.io/nextjs": "workspace:*",
- "ai": "2.2.8",
+ "@typebot.io/prisma": "workspace:*",
+ "ai": "2.1.32",
"aws-sdk": "2.1415.0",
"bot-engine": "workspace:*",
"cors": "2.8.5",
@@ -43,6 +41,7 @@
"@paralleldrive/cuid2": "2.2.1",
"@playwright/test": "1.36.0",
"@typebot.io/emails": "workspace:*",
+ "@typebot.io/env": "workspace:*",
"@typebot.io/lib": "workspace:*",
"@typebot.io/schemas": "workspace:*",
"@typebot.io/tsconfig": "workspace:*",
@@ -53,7 +52,8 @@
"@types/qs": "6.9.7",
"@types/react": "18.2.15",
"@types/sanitize-html": "2.9.0",
- "dotenv": "16.3.1",
+ "dotenv-cli": "^7.2.1",
+ "next-runtime-env": "^1.6.2",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
"google-auth-library": "8.9.0",
diff --git a/apps/viewer/sentry.client.config.js b/apps/viewer/sentry.client.config.js
index a6be194c219..ced7122b496 100644
--- a/apps/viewer/sentry.client.config.js
+++ b/apps/viewer/sentry.client.config.js
@@ -1,9 +1,7 @@
import * as Sentry from '@sentry/nextjs'
-const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
-
Sentry.init({
- dsn: SENTRY_DSN,
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
ignoreErrors: [
'ResizeObserver loop limit exceeded',
'ResizeObserver loop completed with undelivered notifications.',
diff --git a/apps/viewer/sentry.server.config.js b/apps/viewer/sentry.server.config.js
index 466b9f21a30..d6172fa38f0 100644
--- a/apps/viewer/sentry.server.config.js
+++ b/apps/viewer/sentry.server.config.js
@@ -1,8 +1,6 @@
import * as Sentry from '@sentry/nextjs'
-const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN
-
Sentry.init({
- dsn: SENTRY_DSN,
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA + '-viewer',
})
diff --git a/apps/viewer/src/components/ErrorPage.tsx b/apps/viewer/src/components/ErrorPage.tsx
index 42428710d8a..4d3fbea22c6 100644
--- a/apps/viewer/src/components/ErrorPage.tsx
+++ b/apps/viewer/src/components/ErrorPage.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { getViewerUrl, isEmpty } from '@typebot.io/lib'
+import { getViewerUrl } from '@typebot.io/lib'
export const ErrorPage = ({ error }: { error: Error }) => {
return (
@@ -13,7 +13,7 @@ export const ErrorPage = ({ error }: { error: Error }) => {
padding: '0 1rem',
}}
>
- {isEmpty(getViewerUrl()) ? (
+ {!getViewerUrl() ? (
<>
NEXT_PUBLIC_VIEWER_URL is missing
diff --git a/apps/viewer/src/features/blocks/inputs/fileUpload/api/getUploadUrl.ts b/apps/viewer/src/features/blocks/inputs/fileUpload/api/getUploadUrl.ts
index 1f8c7dcfe96..46ecbff4965 100644
--- a/apps/viewer/src/features/blocks/inputs/fileUpload/api/getUploadUrl.ts
+++ b/apps/viewer/src/features/blocks/inputs/fileUpload/api/getUploadUrl.ts
@@ -11,6 +11,7 @@ import {
import { byId, isDefined } from '@typebot.io/lib'
import { z } from 'zod'
import { generatePresignedUrl } from '@typebot.io/lib/api/storage'
+import { env } from '@typebot.io/env'
export const getUploadUrl = publicProcedure
.meta({
@@ -39,11 +40,7 @@ export const getUploadUrl = publicProcedure
})
)
.query(async ({ input: { typebotId, blockId, filePath, fileType } }) => {
- if (
- !process.env.S3_ENDPOINT ||
- !process.env.S3_ACCESS_KEY ||
- !process.env.S3_SECRET_KEY
- )
+ if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message:
diff --git a/apps/viewer/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts b/apps/viewer/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts
index 844b970b8e0..c8db4ad5846 100644
--- a/apps/viewer/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts
+++ b/apps/viewer/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts
@@ -10,6 +10,7 @@ import {
} from '@typebot.io/lib/playwright/databaseActions'
import { getTestAsset } from '@/test/utils/playwright'
import { Plan } from '@typebot.io/prisma'
+import { env } from '@typebot.io/env'
const THREE_GIGABYTES = 3 * 1024 * 1024 * 1024
@@ -30,7 +31,7 @@ test('should work as expected', async ({ page, browser }) => {
await expect(page.locator(`text="3"`)).toBeVisible()
await page.locator('text="Upload 3 files"').click()
await expect(page.locator(`text="3 files uploaded"`)).toBeVisible()
- await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
+ await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.getByRole('link', { name: 'api.json' })).toHaveAttribute(
'href',
/.+\/api\.json/
@@ -52,7 +53,7 @@ test('should work as expected', async ({ page, browser }) => {
const file = readFileSync(downloadPath as string).toString()
const { data } = parse(file)
expect(data).toHaveLength(2)
- expect((data[1] as unknown[])[1]).toContain(process.env.S3_ENDPOINT)
+ expect((data[1] as unknown[])[1]).toContain(env.S3_ENDPOINT)
const urls = (
await Promise.all(
@@ -110,7 +111,7 @@ test.describe('Storage limit is reached', () => {
await page.evaluate(() =>
window.localStorage.setItem('workspaceId', 'starterWorkspace')
)
- await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
+ await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text="150%"')).toBeVisible()
})
})
diff --git a/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts b/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts
index c0ecc0b3b55..b5ec8624b85 100644
--- a/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts
+++ b/apps/viewer/src/features/blocks/integrations/chatwoot/executeChatwootBlock.ts
@@ -2,6 +2,7 @@ import { ExecuteIntegrationResponse } from '@/features/chat/types'
import { extractVariablesFromText } from '@/features/variables/extractVariablesFromText'
import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType'
import { parseVariables } from '@/features/variables/parseVariables'
+import { env } from '@typebot.io/env'
import { isDefined } from '@typebot.io/lib'
import {
ChatwootBlock,
@@ -30,7 +31,7 @@ const parseChatwootOpenCode = ({
const openChatwoot = `${parseSetUserCode(user, resultId)}
window.$chatwoot.setCustomAttributes({
typebot_result_url: "${
- process.env.NEXTAUTH_URL
+ env.NEXTAUTH_URL
}/typebots/${typebotId}/results?id=${resultId}",
});
window.$chatwoot.toggle("open");
diff --git a/apps/viewer/src/features/blocks/integrations/sendEmail/constants.ts b/apps/viewer/src/features/blocks/integrations/sendEmail/constants.ts
index 8a6a40343e9..0c6a0b3ba8b 100644
--- a/apps/viewer/src/features/blocks/integrations/sendEmail/constants.ts
+++ b/apps/viewer/src/features/blocks/integrations/sendEmail/constants.ts
@@ -1,14 +1,16 @@
+import { env } from '@typebot.io/env'
+
export const defaultTransportOptions = {
- host: process.env.SMTP_HOST,
- port: Number(process.env.SMTP_PORT),
- secure: process.env.SMTP_SECURE ? process.env.SMTP_SECURE === 'true' : false,
+ host: env.SMTP_HOST,
+ port: env.SMTP_PORT,
+ secure: env.SMTP_SECURE,
auth: {
- user: process.env.SMTP_USERNAME,
- pass: process.env.SMTP_PASSWORD,
+ user: env.SMTP_USERNAME,
+ pass: env.SMTP_PASSWORD,
},
}
export const defaultFrom = {
- name: process.env.SMTP_FROM?.split(' <')[0].replace(/"/g, ''),
- email: process.env.SMTP_FROM?.match(/<(.*)>/)?.pop(),
+ name: env.NEXT_PUBLIC_SMTP_FROM?.split(' <')[0].replace(/"/g, ''),
+ email: env.NEXT_PUBLIC_SMTP_FROM?.match(/<(.*)>/)?.pop(),
}
diff --git a/apps/viewer/src/features/blocks/integrations/sendEmail/executeSendEmailBlock.tsx b/apps/viewer/src/features/blocks/integrations/sendEmail/executeSendEmailBlock.tsx
index 219bb410a47..23bd92fdc2e 100644
--- a/apps/viewer/src/features/blocks/integrations/sendEmail/executeSendEmailBlock.tsx
+++ b/apps/viewer/src/features/blocks/integrations/sendEmail/executeSendEmailBlock.tsx
@@ -20,6 +20,7 @@ import { decrypt } from '@typebot.io/lib/api'
import { defaultFrom, defaultTransportOptions } from './constants'
import { ExecuteIntegrationResponse } from '@/features/chat/types'
import { findUniqueVariableValue } from '../../../variables/findUniqueVariableValue'
+import { env } from '@typebot.io/env'
export const executeSendEmailBlock = async (
state: SessionState,
@@ -186,7 +187,7 @@ const getEmailInfo = async (
if (credentialsId === 'default')
return {
host: defaultTransportOptions.host,
- port: defaultTransportOptions.port,
+ port: defaultTransportOptions.port ?? 22,
username: defaultTransportOptions.auth.user,
password: defaultTransportOptions.auth.pass,
isTlsEnabled: undefined,
@@ -226,7 +227,7 @@ const getEmailBody = async ({
return {
html: render(
).html,
diff --git a/apps/viewer/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts b/apps/viewer/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
index 29778815309..0105897f763 100644
--- a/apps/viewer/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
+++ b/apps/viewer/src/features/blocks/integrations/sendEmail/sendEmail.spec.ts
@@ -4,6 +4,7 @@ import { createId } from '@paralleldrive/cuid2'
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
import { getTestAsset } from '@/test/utils/playwright'
import { SmtpCredentials } from '@typebot.io/schemas'
+import { env } from '@typebot.io/env'
export const mockSmtpCredentials: SmtpCredentials['data'] = {
from: {
@@ -34,7 +35,7 @@ test('should send an email', async ({ page }) => {
await page.goto(`/${typebotId}-public`)
await page.locator('text=Send email').click()
await expect(page.getByText('Email sent!')).toBeVisible()
- await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
+ await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await page.click('text="See logs"')
await expect(page.locator('text="Email successfully sent"')).toBeVisible()
})
diff --git a/apps/viewer/src/features/blocks/logic/typebotLink/typebotLink.spec.ts b/apps/viewer/src/features/blocks/logic/typebotLink/typebotLink.spec.ts
index 4383ecbc5c8..0e240f92344 100644
--- a/apps/viewer/src/features/blocks/logic/typebotLink/typebotLink.spec.ts
+++ b/apps/viewer/src/features/blocks/logic/typebotLink/typebotLink.spec.ts
@@ -1,5 +1,6 @@
import { getTestAsset } from '@/test/utils/playwright'
import test, { expect } from '@playwright/test'
+import { env } from '@typebot.io/env'
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
@@ -33,7 +34,7 @@ test('should work as expected', async ({ page }) => {
await page.locator('input').fill('Hello there!')
await page.locator('input').press('Enter')
await expect(page.getByText('Cheers!')).toBeVisible()
- await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
+ await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text=Hello there!')).toBeVisible()
})
diff --git a/apps/viewer/src/features/chat/api/sendMessage.ts b/apps/viewer/src/features/chat/api/sendMessage.ts
index 7898b6d2984..203ea856b67 100644
--- a/apps/viewer/src/features/chat/api/sendMessage.ts
+++ b/apps/viewer/src/features/chat/api/sendMessage.ts
@@ -16,7 +16,7 @@ import {
Variable,
VariableWithValue,
} from '@typebot.io/schemas'
-import { env, isDefined, isNotEmpty, omit } from '@typebot.io/lib'
+import { isDefined, isNotEmpty, omit } from '@typebot.io/lib'
import { prefillVariables } from '@/features/variables/prefillVariables'
import { injectVariablesFromExistingResult } from '@/features/variables/injectVariablesFromExistingResult'
import { deepParseVariables } from '@/features/variables/deepParseVariable'
@@ -30,6 +30,7 @@ import { findTypebot } from '../queries/findTypebot'
import { findPublicTypebot } from '../queries/findPublicTypebot'
import { findResult } from '../queries/findResult'
import { createId } from '@paralleldrive/cuid2'
+import { env } from '@typebot.io/env'
export const sendMessage = publicProcedure
.meta({
@@ -257,7 +258,7 @@ const getTypebot = async (
userId?: string
): Promise => {
if (typeof typebot !== 'string') return typebot
- if (isPreview && !userId && env('E2E_TEST') !== 'true')
+ if (isPreview && !userId && !env.NEXT_PUBLIC_E2E_TEST)
throw new TRPCError({
code: 'UNAUTHORIZED',
message:
diff --git a/apps/viewer/src/features/results/results.spec.ts b/apps/viewer/src/features/results/results.spec.ts
index cd52c2100c1..5b0764c105b 100644
--- a/apps/viewer/src/features/results/results.spec.ts
+++ b/apps/viewer/src/features/results/results.spec.ts
@@ -2,6 +2,7 @@ import { getTestAsset } from '@/test/utils/playwright'
import test, { expect } from '@playwright/test'
import { createId } from '@paralleldrive/cuid2'
import { importTypebotInDatabase } from '@typebot.io/lib/playwright/databaseActions'
+import { env } from '@typebot.io/env'
test('Big groups should work as expected', async ({ page }) => {
const typebotId = createId()
@@ -15,7 +16,7 @@ test('Big groups should work as expected', async ({ page }) => {
await page.locator('input').fill('26')
await page.locator('input').press('Enter')
await page.getByRole('button', { name: 'Yes' }).click()
- await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
+ await page.goto(`${env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text="Baptiste"')).toBeVisible()
await expect(page.locator('text="26"')).toBeVisible()
await expect(page.locator('text="Yes"')).toBeVisible()
diff --git a/apps/viewer/src/helpers/api/dbRules.ts b/apps/viewer/src/helpers/api/dbRules.ts
index aa9f32d6da2..4a006834f29 100644
--- a/apps/viewer/src/helpers/api/dbRules.ts
+++ b/apps/viewer/src/helpers/api/dbRules.ts
@@ -4,7 +4,7 @@ import {
User,
WorkspaceRole,
} from '@typebot.io/prisma'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
const parseWhereFilter = (
typebotIds: string[] | string,
@@ -24,8 +24,8 @@ const parseWhereFilter = (
{
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
workspace:
- (type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
- env('E2E_TEST') === 'true'
+ (type === 'read' && user.email === env.ADMIN_EMAIL) ||
+ env.NEXT_PUBLIC_E2E_TEST
? undefined
: {
members: {
diff --git a/apps/viewer/src/helpers/api/isPlanetScale.ts b/apps/viewer/src/helpers/api/isPlanetScale.ts
index 88f67e70bb0..9b896199ee8 100644
--- a/apps/viewer/src/helpers/api/isPlanetScale.ts
+++ b/apps/viewer/src/helpers/api/isPlanetScale.ts
@@ -1,2 +1,3 @@
-export const isPlaneteScale = () =>
- process.env.DATABASE_URL?.includes('pscale_pw')
+import { env } from '@typebot.io/env'
+
+export const isPlaneteScale = () => env.DATABASE_URL?.includes('pscale_pw')
diff --git a/apps/viewer/src/helpers/api/isVercel.ts b/apps/viewer/src/helpers/api/isVercel.ts
index b7d221f41d1..64a882ff96b 100644
--- a/apps/viewer/src/helpers/api/isVercel.ts
+++ b/apps/viewer/src/helpers/api/isVercel.ts
@@ -1,3 +1,3 @@
-import { isDefined } from '@typebot.io/lib/utils'
+import { env } from '@typebot.io/env'
-export const isVercel = () => isDefined(process.env.NEXT_PUBLIC_VERCEL_ENV)
+export const isVercel = () => env.NEXT_PUBLIC_VERCEL_ENV
diff --git a/apps/viewer/src/lib/google-sheets.ts b/apps/viewer/src/lib/google-sheets.ts
index 77205e6bbfd..0a573e7b1ba 100644
--- a/apps/viewer/src/lib/google-sheets.ts
+++ b/apps/viewer/src/lib/google-sheets.ts
@@ -4,6 +4,7 @@ import { GoogleSheetsCredentials } from '@typebot.io/schemas'
import { isDefined } from '@typebot.io/lib'
import { decrypt, encrypt } from '@typebot.io/lib/api'
import prisma from './prisma'
+import { env } from '@typebot.io/env'
export const getAuthenticatedGoogleClient = async (
credentialsId: string
@@ -18,9 +19,9 @@ export const getAuthenticatedGoogleClient = async (
)) as GoogleSheetsCredentials['data']
const oauth2Client = new OAuth2Client(
- process.env.GOOGLE_CLIENT_ID,
- process.env.GOOGLE_CLIENT_SECRET,
- `${process.env.NEXTAUTH_URL}/api/credentials/google-sheets/callback`
+ env.GOOGLE_CLIENT_ID,
+ env.GOOGLE_CLIENT_SECRET,
+ `${env.NEXTAUTH_URL}/api/credentials/google-sheets/callback`
)
oauth2Client.setCredentials(data)
oauth2Client.on('tokens', updateTokens(credentialsId, data))
diff --git a/apps/viewer/src/lib/prisma.ts b/apps/viewer/src/lib/prisma.ts
index 093b1eaac67..2a536817fae 100644
--- a/apps/viewer/src/lib/prisma.ts
+++ b/apps/viewer/src/lib/prisma.ts
@@ -1,9 +1,10 @@
+import { env } from '@typebot.io/env'
import { PrismaClient } from '@typebot.io/prisma'
declare const global: { prisma: PrismaClient }
let prisma: PrismaClient
-if (process.env.NODE_ENV === 'production') {
+if (env.NODE_ENV === 'production') {
prisma = new PrismaClient()
} else {
if (!global.prisma) {
diff --git a/apps/viewer/src/pages/[[...publicId]].tsx b/apps/viewer/src/pages/[[...publicId]].tsx
index cb3c591f957..1a4c12284b6 100644
--- a/apps/viewer/src/pages/[[...publicId]].tsx
+++ b/apps/viewer/src/pages/[[...publicId]].tsx
@@ -2,10 +2,11 @@ import { IncomingMessage } from 'http'
import { ErrorPage } from '@/components/ErrorPage'
import { NotFoundPage } from '@/components/NotFoundPage'
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
-import { env, getViewerUrl, isNotDefined } from '@typebot.io/lib'
+import { isNotDefined } from '@typebot.io/lib'
import prisma from '../lib/prisma'
import { TypebotPageProps, TypebotPageV2 } from '@/components/TypebotPageV2'
import { TypebotPageV3, TypebotV3PageProps } from '@/components/TypebotPageV3'
+import { env } from '@typebot.io/env'
// Browsers that doesn't support ES modules and/or web components
const incompatibleBrowsers = [
@@ -24,7 +25,7 @@ const incompatibleBrowsers = [
]
const log = (message: string) => {
- if (process.env.DEBUG !== 'true') return
+ if (!env.DEBUG) return
console.log(`[DEBUG] ${message}`)
}
@@ -41,19 +42,18 @@ export const getServerSideProps: GetServerSideProps = async (
log(`forwardedHost: ${forwardedHost}`)
try {
if (!host) return { props: {} }
- const viewerUrls = (getViewerUrl({ returnAll: true }) ?? '').split(',')
+ const viewerUrls = env.NEXT_PUBLIC_VIEWER_URL
log(`viewerUrls: ${viewerUrls}`)
- const isMatchingViewerUrl =
- env('E2E_TEST') === 'true'
- ? true
- : viewerUrls.some(
- (url) =>
- host.split(':')[0].includes(url.split('//')[1].split(':')[0]) ||
- (forwardedHost &&
- forwardedHost
- .split(':')[0]
- .includes(url.split('//')[1].split(':')[0]))
- )
+ const isMatchingViewerUrl = env.NEXT_PUBLIC_E2E_TEST
+ ? true
+ : viewerUrls?.some(
+ (url) =>
+ host.split(':')[0].includes(url.split('//')[1].split(':')[0]) ||
+ (forwardedHost &&
+ forwardedHost
+ .split(':')[0]
+ .includes(url.split('//')[1].split(':')[0]))
+ )
log(`isMatchingViewerUrl: ${isMatchingViewerUrl}`)
const customDomain = `${forwardedHost ?? host}${
pathname === '/' ? '' : pathname
diff --git a/apps/viewer/src/pages/_document.tsx b/apps/viewer/src/pages/_document.tsx
index 07dbb3260ef..d81eac8fa16 100644
--- a/apps/viewer/src/pages/_document.tsx
+++ b/apps/viewer/src/pages/_document.tsx
@@ -4,7 +4,7 @@ import { Html, Head, Main, NextScript } from 'next/document'
const Document = () => (
-
+
diff --git a/apps/viewer/src/pages/api/integrations/openai/streamer.ts b/apps/viewer/src/pages/api/integrations/openai/streamer.ts
index c6bd98e086a..ddc4b8a68d4 100644
--- a/apps/viewer/src/pages/api/integrations/openai/streamer.ts
+++ b/apps/viewer/src/pages/api/integrations/openai/streamer.ts
@@ -1,5 +1,6 @@
import { getChatCompletionStream } from '@/features/blocks/integrations/openai/getChatCompletionStream'
import { connect } from '@planetscale/database'
+import { env } from '@typebot.io/env'
import { IntegrationBlockType, SessionState } from '@typebot.io/schemas'
import { StreamingTextResponse } from 'ai'
import { ChatCompletionRequestMessage } from 'openai'
@@ -29,7 +30,7 @@ const handler = async (req: Request) => {
if (!messages) return new Response('No messages provided', { status: 400 })
- const conn = connect({ url: process.env.DATABASE_URL })
+ const conn = connect({ url: env.DATABASE_URL })
const chatSession = await conn.execute(
'select state from ChatSession where id=?',
diff --git a/apps/viewer/src/pages/api/typebots/[typebotId]/integrations/email.tsx b/apps/viewer/src/pages/api/typebots/[typebotId]/integrations/email.tsx
index 8d37089276b..4c8d28d3af7 100644
--- a/apps/viewer/src/pages/api/typebots/[typebotId]/integrations/email.tsx
+++ b/apps/viewer/src/pages/api/typebots/[typebotId]/integrations/email.tsx
@@ -17,22 +17,23 @@ import { render } from '@faire/mjml-react/utils/render'
import prisma from '@/lib/prisma'
import { saveErrorLog } from '@/features/logs/saveErrorLog'
import { saveSuccessLog } from '@/features/logs/saveSuccessLog'
+import { env } from '@typebot.io/env'
const cors = initMiddleware(Cors())
const defaultTransportOptions = {
- host: process.env.SMTP_HOST,
- port: Number(process.env.SMTP_PORT),
- secure: process.env.SMTP_SECURE ? process.env.SMTP_SECURE === 'true' : false,
+ host: env.SMTP_HOST,
+ port: env.SMTP_PORT,
+ secure: env.SMTP_SECURE,
auth: {
- user: process.env.SMTP_USERNAME,
- pass: process.env.SMTP_PASSWORD,
+ user: env.SMTP_USERNAME,
+ pass: env.SMTP_PASSWORD,
},
}
const defaultFrom = {
- name: process.env.SMTP_FROM?.split(' <')[0].replace(/"/g, ''),
- email: process.env.SMTP_FROM?.match(/<(.*)>/)?.pop(),
+ name: env.NEXT_PUBLIC_SMTP_FROM?.split(' <')[0].replace(/"/g, ''),
+ email: env.NEXT_PUBLIC_SMTP_FROM?.match(/<(.*)>/)?.pop(),
}
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
@@ -159,7 +160,7 @@ const getEmailInfo = async (
if (credentialsId === 'default')
return {
host: defaultTransportOptions.host,
- port: defaultTransportOptions.port,
+ port: defaultTransportOptions.port as number,
username: defaultTransportOptions.auth.user,
password: defaultTransportOptions.auth.pass,
isTlsEnabled: undefined,
@@ -213,7 +214,7 @@ const getEmailBody = async ({
return {
html: render(
).html,
diff --git a/docker-compose.build.yml b/docker-compose.build.yml
index f10dc4fbf96..b269a4afde3 100644
--- a/docker-compose.build.yml
+++ b/docker-compose.build.yml
@@ -4,7 +4,7 @@ services:
image: postgres:13
restart: always
volumes:
- - build_db_data:/var/lib/postgresql/data
+ - ${PWD}/.typebot-build/database:/var/lib/postgresql/data
environment:
- POSTGRES_DB=typebot
- POSTGRES_PASSWORD=typebot
@@ -19,16 +19,7 @@ services:
- '8080:3000'
extra_hosts:
- 'host.docker.internal:host-gateway'
- # See https://docs.typebot.io/self-hosting/configuration for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXTAUTH_URL=http://localhost:8080
- - NEXT_PUBLIC_VIEWER_URL=http://localhost:8081
- - ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
- - ADMIN_EMAIL=me@email.com
- - NEXTAUTH_URL_INTERNAL=http://host.docker.internal:8080
- - GITHUB_CLIENT_ID=37a279454d016598c2df
- - GITHUB_CLIENT_SECRET=4b288a509352b591cd4478e3ac901668b2f8ed03
+ env_file: .env
typebot-viewer:
build:
context: .
@@ -36,10 +27,4 @@ services:
- SCOPE=viewer
ports:
- '8081:3000'
- # See https://docs.typebot.io/self-hosting/configuration for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXT_PUBLIC_VIEWER_URL=http://localhost:8081
- - ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
-volumes:
- build_db_data:
+ env_file: .env
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index 357eccc20cc..5723331fe6a 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -1,6 +1,6 @@
version: '3.3'
services:
- postgres:
+ typebot-db:
image: postgres:13
ports:
- '5432:5432'
diff --git a/docker-compose.yml b/docker-compose.yml
index 796b36bd9d1..b0fb16fb855 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,7 +4,7 @@ services:
image: postgres:13
restart: always
volumes:
- - db_data:/var/lib/postgresql/data
+ - ${PWD}/.typebot/database:/var/lib/postgresql/data
environment:
- POSTGRES_DB=typebot
- POSTGRES_PASSWORD=typebot
@@ -17,23 +17,10 @@ services:
- '8080:3000'
extra_hosts:
- 'host.docker.internal:host-gateway'
- # See https://docs.typebot.io/self-hosting/configuration/builder for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXTAUTH_URL=
- - NEXT_PUBLIC_VIEWER_URL=
- - ENCRYPTION_SECRET=
- - ADMIN_EMAIL=
+ env_file: .env
typebot-viewer:
image: baptistearno/typebot-viewer:latest
restart: always
ports:
- '8081:3000'
- # See https://docs.typebot.io/self-hosting/configuration/viewer for more configuration options
- environment:
- - DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
- - NEXT_PUBLIC_VIEWER_URL=
- - ENCRYPTION_SECRET=
- - NEXTAUTH_URL=
-volumes:
- db_data:
+ env_file: .env
diff --git a/package.json b/package.json
index 6930ad71f1d..6e1aa34cc80 100644
--- a/package.json
+++ b/package.json
@@ -8,12 +8,8 @@
"docker:up": "docker compose -f docker-compose.dev.yml up -d && sleep 5",
"docker:nuke": "docker compose -f docker-compose.dev.yml down --volumes --remove-orphans",
"lint": "turbo run lint",
- "dev": "pnpm docker:up && cross-env NEXT_PUBLIC_E2E_TEST=false turbo build --filter=@typebot.io/nextjs... && cross-env NEXT_PUBLIC_E2E_TEST=false turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
- "dev:mocking": "pnpm docker:up && cross-env NEXT_PUBLIC_E2E_TEST=false turbo build --filter=@typebot.io/nextjs... && cross-env NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
+ "dev": "pnpm docker:up && turbo build --filter=@typebot.io/nextjs... && turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
"build": "pnpm docker:up && turbo run build",
- "build:builder": "turbo run build --filter=builder... && turbo run build:env --filter=builder...",
- "build:viewer": "turbo run build --filter=viewer... && turbo run build:env --filter=viewer...",
- "build:landing-page": "turbo run build --filter=landing-page... && turbo run build:env --filter=landing-page...",
"build:apps": "turbo run build --filter=builder... --filter=viewer...",
"db:migrate": "cd packages/prisma && pnpm run db:migrate",
"generate-change-log": "git fetch --all && pnpx gitmoji-changelog"
diff --git a/packages/emails/package.json b/packages/emails/package.json
index 50ff58811ba..9c3f3bd0c42 100644
--- a/packages/emails/package.json
+++ b/packages/emails/package.json
@@ -27,7 +27,8 @@
"@typebot.io/lib": "workspace:*",
"eslint": "8.44.0",
"eslint-config-custom": "workspace:*",
- "@typebot.io/tsconfig": "workspace:*"
+ "@typebot.io/tsconfig": "workspace:*",
+ "@typebot.io/env": "workspace:*"
},
"peerDependencies": {
"@faire/mjml-react": "2.1.4",
diff --git a/packages/emails/src/sendEmail.ts b/packages/emails/src/sendEmail.ts
index 1dbff4a6678..bfe8a78c094 100644
--- a/packages/emails/src/sendEmail.ts
+++ b/packages/emails/src/sendEmail.ts
@@ -1,20 +1,20 @@
import { createTransport, SendMailOptions } from 'nodemailer'
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
export const sendEmail = (
props: Pick
) => {
const transporter = createTransport({
- host: process.env.SMTP_HOST,
- port: Number(process.env.SMTP_PORT),
+ host: env.SMTP_HOST,
+ port: env.SMTP_PORT,
auth: {
- user: process.env.SMTP_USERNAME,
- pass: process.env.SMTP_PASSWORD,
+ user: env.SMTP_USERNAME,
+ pass: env.SMTP_PASSWORD,
},
})
return transporter.sendMail({
- from: process.env.SMTP_FROM ?? env('SMTP_FROM'),
+ from: env.NEXT_PUBLIC_SMTP_FROM,
...props,
})
}
diff --git a/packages/embeds/js/package.json b/packages/embeds/js/package.json
index ca3c78a05bd..0020cad6369 100644
--- a/packages/embeds/js/package.json
+++ b/packages/embeds/js/package.json
@@ -25,6 +25,7 @@
"@rollup/plugin-terser": "0.4.3",
"@rollup/plugin-typescript": "11.1.2",
"@typebot.io/lib": "workspace:*",
+ "@typebot.io/env": "workspace:*",
"@typebot.io/schemas": "workspace:*",
"@typebot.io/tsconfig": "workspace:*",
"autoprefixer": "10.4.14",
diff --git a/packages/embeds/js/src/utils/guessApiHost.ts b/packages/embeds/js/src/utils/guessApiHost.ts
index df3a8a7d807..914b457a876 100644
--- a/packages/embeds/js/src/utils/guessApiHost.ts
+++ b/packages/embeds/js/src/utils/guessApiHost.ts
@@ -1,8 +1,8 @@
-import { env } from '@typebot.io/lib'
+import { env } from '@typebot.io/env'
const cloudViewerUrl = 'https://viewer.typebot.io'
export const guessApiHost = () =>
- env('VIEWER_INTERNAL_URL') ??
- env('VIEWER_URL')?.split(',')[0] ??
+ env.NEXT_PUBLIC_VIEWER_INTERNAL_URL ??
+ env.NEXT_PUBLIC_VIEWER_URL?.[0] ??
cloudViewerUrl
diff --git a/packages/embeds/react/.env.local.example b/packages/embeds/react/.env.local.example
deleted file mode 100644
index b6832edf33e..00000000000
--- a/packages/embeds/react/.env.local.example
+++ /dev/null
@@ -1 +0,0 @@
-DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
\ No newline at end of file
diff --git a/packages/env/env.ts b/packages/env/env.ts
new file mode 100644
index 00000000000..400cb37cb85
--- /dev/null
+++ b/packages/env/env.ts
@@ -0,0 +1,313 @@
+import { createEnv } from '@t3-oss/env-nextjs'
+import { z } from 'zod'
+
+declare const window: {
+ __ENV: any
+}
+
+const readVariable = (key: string) => {
+ if (typeof window === 'undefined') return process.env[key]
+ return window.__ENV[key]
+}
+
+const boolean = z.enum(['true', 'false']).transform((value) => value === 'true')
+
+const baseEnv = {
+ server: {
+ NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
+ DATABASE_URL: z
+ .string()
+ .url()
+ .refine((url) => url.startsWith('postgres') || url.startsWith('mysql')),
+ ENCRYPTION_SECRET: z.string().length(32),
+ NEXTAUTH_URL: z.string().url(),
+ DISABLE_SIGNUP: boolean.optional(),
+ ADMIN_EMAIL: z.string().email().optional(),
+ DEFAULT_WORKSPACE_PLAN: z
+ .enum(['FREE', 'STARTER', 'PRO', 'LIFETIME', 'UNLIMITED'])
+ .refine((str) =>
+ ['FREE', 'STARTER', 'PRO', 'LIFETIME', 'UNLIMITED'].includes(str)
+ )
+ .default('FREE'),
+ DEBUG: boolean.optional(),
+ },
+ client: {
+ NEXT_PUBLIC_E2E_TEST: boolean.optional(),
+ NEXT_PUBLIC_VIEWER_URL: z
+ .string()
+ .optional()
+ .transform((string) => (string ? string.split(',') : undefined)),
+ NEXT_PUBLIC_VIEWER_INTERNAL_URL: z.string().url().optional(),
+ NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_E2E_TEST: readVariable('NEXT_PUBLIC_E2E_TEST'),
+ NEXT_PUBLIC_VIEWER_URL: readVariable('NEXT_PUBLIC_VIEWER_URL'),
+ NEXT_PUBLIC_VIEWER_INTERNAL_URL: readVariable(
+ 'NEXT_PUBLIC_VIEWER_INTERNAL_URL'
+ ),
+ NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID: readVariable(
+ 'NEXT_PUBLIC_ONBOARDING_TYPEBOT_ID'
+ ),
+ },
+}
+const githubEnv = {
+ server: {
+ GITHUB_CLIENT_ID: z.string().min(1).optional(),
+ GITHUB_CLIENT_SECRET: z.string().min(1).optional(),
+ },
+}
+
+const facebookEnv = {
+ server: {
+ FACEBOOK_CLIENT_ID: z.string().min(1).optional(),
+ FACEBOOK_CLIENT_SECRET: z.string().min(1).optional(),
+ },
+}
+
+const smtpEnv = {
+ server: {
+ SMTP_USERNAME: z.string().min(1).optional(),
+ SMTP_PASSWORD: z.string().min(1).optional(),
+ SMTP_HOST: z.string().min(1).optional(),
+ SMTP_PORT: z.coerce.number().optional(),
+ SMTP_AUTH_DISABLED: boolean.optional(),
+ SMTP_SECURE: boolean.optional(),
+ },
+ client: {
+ NEXT_PUBLIC_SMTP_FROM: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_SMTP_FROM: readVariable('NEXT_PUBLIC_SMTP_FROM'),
+ },
+}
+
+const gitlabEnv = {
+ server: {
+ GITLAB_CLIENT_ID: z.string().min(1).optional(),
+ GITLAB_CLIENT_SECRET: z.string().min(1).optional(),
+ GITLAB_BASE_URL: z.string().url().optional(),
+ GITLAB_NAME: z.string().min(1).optional(),
+ GITLAB_REQUIRED_GROUPS: z
+ .string()
+ .transform((string) => (string ? string.split(',') : undefined))
+ .optional(),
+ },
+}
+
+const azureEnv = {
+ server: {
+ AZURE_AD_CLIENT_ID: z.string().min(1).optional(),
+ AZURE_AD_CLIENT_SECRET: z.string().min(1).optional(),
+ AZURE_AD_TENANT_ID: z.string().min(1).optional(),
+ },
+}
+
+const customOAuthEnv = {
+ server: {
+ CUSTOM_OAUTH_NAME: z.string().min(1).optional(),
+ CUSTOM_OAUTH_SCOPE: z.string().min(1).optional(),
+ CUSTOM_OAUTH_CLIENT_ID: z.string().min(1).optional(),
+ CUSTOM_OAUTH_CLIENT_SECRET: z.string().min(1).optional(),
+ CUSTOM_OAUTH_WELL_KNOWN_URL: z.string().url().optional(),
+ CUSTOM_OAUTH_USER_ID_PATH: z.string().min(1).optional(),
+ CUSTOM_OAUTH_USER_EMAIL_PATH: z.string().min(1).optional(),
+ CUSTOM_OAUTH_USER_NAME_PATH: z.string().min(1).optional(),
+ CUSTOM_OAUTH_USER_IMAGE_PATH: z.string().min(1).optional(),
+ },
+}
+
+const googleEnv = {
+ server: {
+ GOOGLE_CLIENT_ID: z.string().min(1).optional(),
+ GOOGLE_CLIENT_SECRET: z.string().min(1).optional(),
+ },
+ client: {
+ NEXT_PUBLIC_GOOGLE_API_KEY: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_GOOGLE_API_KEY: readVariable('NEXT_PUBLIC_GOOGLE_API_KEY'),
+ },
+}
+
+const stripeEnv = {
+ server: {
+ STRIPE_SECRET_KEY: z.string().min(1).optional(),
+ STRIPE_WEBHOOK_SECRET: z.string().min(1).optional(),
+ STRIPE_STARTER_PRODUCT_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_CHATS_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_CHATS_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_STORAGE_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_STARTER_STORAGE_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_PRODUCT_ID: z.string().min(1).optional(),
+ STRIPE_PRO_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_CHATS_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_CHATS_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_STORAGE_MONTHLY_PRICE_ID: z.string().min(1).optional(),
+ STRIPE_PRO_STORAGE_YEARLY_PRICE_ID: z.string().min(1).optional(),
+ },
+ client: {
+ NEXT_PUBLIC_STRIPE_PUBLIC_KEY: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_STRIPE_PUBLIC_KEY: readVariable(
+ 'NEXT_PUBLIC_STRIPE_PUBLIC_KEY'
+ ),
+ },
+}
+
+const s3Env = {
+ server: {
+ S3_ACCESS_KEY: z.string().min(1).optional(),
+ S3_SECRET_KEY: z.string().min(1).optional(),
+ S3_BUCKET: z.string().min(1).optional(),
+ S3_PORT: z.coerce.number().optional(),
+ S3_ENDPOINT: z.string().min(1).optional(),
+ S3_SSL: boolean.optional(),
+ S3_REGION: z.string().min(1).optional(),
+ },
+}
+
+const giphyEnv = {
+ client: {
+ NEXT_PUBLIC_GIPHY_API_KEY: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_GIPHY_API_KEY: readVariable('NEXT_PUBLIC_GIPHY_API_KEY'),
+ },
+}
+
+const vercelEnv = {
+ server: {
+ VERCEL_TOKEN: z.string().min(1).optional(),
+ VERCEL_TEAM_ID: z.string().min(1).optional(),
+ VERCEL_GIT_COMMIT_SHA: z.string().min(1).optional(),
+ },
+ client: {
+ NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME: z.string().min(1).optional(),
+ NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: z.string().min(1).optional(),
+ NEXT_PUBLIC_VERCEL_ENV: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME: readVariable(
+ 'NEXT_PUBLIC_VERCEL_VIEWER_PROJECT_NAME'
+ ),
+ NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA: readVariable(
+ 'NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA'
+ ),
+ NEXT_PUBLIC_VERCEL_ENV: readVariable('NEXT_PUBLIC_VERCEL_ENV'),
+ },
+}
+
+const sleekPlanEnv = {
+ server: {
+ SLEEKPLAN_SSO_KEY: z.string().min(1).optional(),
+ },
+}
+
+const unsplashEnv = {
+ client: {
+ NEXT_PUBLIC_UNSPLASH_APP_NAME: z.string().min(1).optional(),
+ NEXT_PUBLIC_UNSPLASH_ACCESS_KEY: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_UNSPLASH_APP_NAME: readVariable(
+ 'NEXT_PUBLIC_UNSPLASH_APP_NAME'
+ ),
+ NEXT_PUBLIC_UNSPLASH_ACCESS_KEY: readVariable(
+ 'NEXT_PUBLIC_UNSPLASH_ACCESS_KEY'
+ ),
+ },
+}
+
+const whatsAppEnv = {
+ server: {
+ META_SYSTEM_USER_TOKEN: z.string().min(1).optional(),
+ WHATSAPP_PREVIEW_FROM_PHONE_NUMBER_ID: z.string().min(1).optional(),
+ },
+}
+
+const upstashRedis = {
+ server: {
+ UPSTASH_REDIS_REST_URL: z.string().url().optional(),
+ UPSTASH_REDIS_REST_TOKEN: z.string().min(1).optional(),
+ },
+}
+
+const sentryEnv = {
+ client: {
+ NEXT_PUBLIC_SENTRY_DSN: z.string().min(1).optional(),
+ },
+ server: {
+ SENTRY_AUTH_TOKEN: z.string().min(1).optional(),
+ SENTRY_PROJECT: z.string().min(1).optional(),
+ SENTRY_ORG: z.string().min(1).optional(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_SENTRY_DSN: readVariable('NEXT_PUBLIC_SENTRY_DSN'),
+ },
+}
+
+const telemetryEnv = {
+ server: {
+ TELEMETRY_WEBHOOK_URL: z.string().url().optional(),
+ TELEMETRY_WEBHOOK_BEARER_TOKEN: z.string().min(1).optional(),
+ USER_CREATED_WEBHOOK_URL: z.string().url().optional(),
+ },
+}
+
+const posthogEnv = {
+ server: {
+ POSTHOG_API_KEY: z.string().min(1).optional(),
+ },
+}
+
+export const env = createEnv({
+ server: {
+ ...baseEnv.server,
+ ...githubEnv.server,
+ ...facebookEnv.server,
+ ...smtpEnv.server,
+ ...googleEnv.server,
+ ...stripeEnv.server,
+ ...s3Env.server,
+ ...vercelEnv.server,
+ ...sleekPlanEnv.server,
+ ...whatsAppEnv.server,
+ ...upstashRedis.server,
+ ...gitlabEnv.server,
+ ...azureEnv.server,
+ ...customOAuthEnv.server,
+ ...sentryEnv.server,
+ ...telemetryEnv.server,
+ ...posthogEnv.server,
+ },
+ client: {
+ ...baseEnv.client,
+ ...smtpEnv.client,
+ ...googleEnv.client,
+ ...stripeEnv.client,
+ ...giphyEnv.client,
+ ...vercelEnv.client,
+ ...unsplashEnv.client,
+ ...sentryEnv.client,
+ },
+ experimental__runtimeEnv: {
+ ...baseEnv.runtimeEnv,
+ ...smtpEnv.runtimeEnv,
+ ...googleEnv.runtimeEnv,
+ ...stripeEnv.runtimeEnv,
+ ...giphyEnv.runtimeEnv,
+ ...vercelEnv.runtimeEnv,
+ ...unsplashEnv.runtimeEnv,
+ ...sentryEnv.runtimeEnv,
+ },
+ // onInvalidAccess: (variable: string) => {
+ // throw new Error(
+ // `❌ Attempted to access a server-side environment variable on the client: ${variable}`
+ // )
+ // },
+})
diff --git a/packages/env/package.json b/packages/env/package.json
new file mode 100644
index 00000000000..2ef96c39bff
--- /dev/null
+++ b/packages/env/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "@typebot.io/env",
+ "version": "1.0.0",
+ "license": "AGPL-3.0-or-later",
+ "private": true,
+ "main": "./env.ts",
+ "types": "./env.ts",
+ "dependencies": {
+ "@t3-oss/env-nextjs": "^0.6.0",
+ "zod": "3.21.4"
+ },
+ "devDependencies": {
+ "@typebot.io/tsconfig": "workspace:*",
+ "@types/node": "^20.4.9",
+ "esbuild": "^0.19.1"
+ },
+ "scripts": {
+ "build": "esbuild env.ts --packages=external --outfile=dist/env.mjs"
+ }
+}
diff --git a/packages/env/tsconfig.json b/packages/env/tsconfig.json
new file mode 100644
index 00000000000..57c1b523766
--- /dev/null
+++ b/packages/env/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "@typebot.io/tsconfig/base.json",
+ "include": ["**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/packages/lib/api/encryption.ts b/packages/lib/api/encryption.ts
index c3d33d937fe..0d5af3fcc6d 100644
--- a/packages/lib/api/encryption.ts
+++ b/packages/lib/api/encryption.ts
@@ -1,8 +1,9 @@
import { Credentials } from '@typebot.io/schemas/features/credentials'
import { decryptV1 } from './encryptionV1'
+import { env } from '@typebot.io/env'
const algorithm = 'AES-GCM'
-const secretKey = process.env.ENCRYPTION_SECRET
+const secretKey = env.ENCRYPTION_SECRET
export const encrypt = async (
data: object
diff --git a/packages/lib/api/encryptionV1.ts b/packages/lib/api/encryptionV1.ts
index 9b083175099..628a7a2d010 100644
--- a/packages/lib/api/encryptionV1.ts
+++ b/packages/lib/api/encryptionV1.ts
@@ -1,7 +1,8 @@
+import { env } from '@typebot.io/env'
import { createDecipheriv } from 'crypto'
const algorithm = 'aes-256-gcm'
-const secretKey = process.env.ENCRYPTION_SECRET
+const secretKey = env.ENCRYPTION_SECRET
export const decryptV1 = (encryptedData: string, auth: string): object => {
if (!secretKey) throw new Error(`ENCRYPTION_SECRET is not in environment`)
diff --git a/packages/lib/api/helpers/archiveResults.ts b/packages/lib/api/helpers/archiveResults.ts
index 9145e84d892..feef833a743 100644
--- a/packages/lib/api/helpers/archiveResults.ts
+++ b/packages/lib/api/helpers/archiveResults.ts
@@ -1,3 +1,4 @@
+import { env } from '@typebot.io/env'
import { Prisma, PrismaClient } from '@typebot.io/prisma'
import { InputBlockType, Typebot } from '@typebot.io/schemas'
import { Client } from 'minio'
@@ -95,32 +96,26 @@ const deleteFilesFromBucket = async ({
}: {
urls: string[]
}): Promise => {
- if (
- !process.env.S3_ENDPOINT ||
- !process.env.S3_ACCESS_KEY ||
- !process.env.S3_SECRET_KEY
- )
+ if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
throw new Error(
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY'
)
- const useSSL =
- process.env.S3_SSL && process.env.S3_SSL === 'false' ? false : true
const minioClient = new Client({
- endPoint: process.env.S3_ENDPOINT,
- port: process.env.S3_PORT ? parseInt(process.env.S3_PORT) : undefined,
- useSSL,
- accessKey: process.env.S3_ACCESS_KEY,
- secretKey: process.env.S3_SECRET_KEY,
- region: process.env.S3_REGION,
+ endPoint: env.S3_ENDPOINT,
+ port: env.S3_PORT,
+ useSSL: env.S3_SSL,
+ accessKey: env.S3_ACCESS_KEY,
+ secretKey: env.S3_SECRET_KEY,
+ region: env.S3_REGION,
})
- const bucket = process.env.S3_BUCKET ?? 'typebot'
+ const bucket = env.S3_BUCKET ?? 'typebot'
return minioClient.removeObjects(
bucket,
urls
- .filter((url) => url.includes(process.env.S3_ENDPOINT as string))
+ .filter((url) => url.includes(env.S3_ENDPOINT as string))
.map((url) => url.split(`/${bucket}/`)[1])
)
}
diff --git a/packages/lib/api/pricing.ts b/packages/lib/api/pricing.ts
new file mode 100644
index 00000000000..770c683390b
--- /dev/null
+++ b/packages/lib/api/pricing.ts
@@ -0,0 +1,33 @@
+import { env } from '@typebot.io/env'
+import { Plan } from '@typebot.io/prisma'
+
+export const priceIds = {
+ [Plan.STARTER]: {
+ base: {
+ monthly: env.STRIPE_STARTER_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_STARTER_YEARLY_PRICE_ID,
+ },
+ chats: {
+ monthly: env.STRIPE_STARTER_CHATS_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_STARTER_CHATS_YEARLY_PRICE_ID,
+ },
+ storage: {
+ monthly: env.STRIPE_STARTER_STORAGE_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_STARTER_STORAGE_YEARLY_PRICE_ID,
+ },
+ },
+ [Plan.PRO]: {
+ base: {
+ monthly: env.STRIPE_PRO_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_PRO_YEARLY_PRICE_ID,
+ },
+ chats: {
+ monthly: env.STRIPE_PRO_CHATS_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_PRO_CHATS_YEARLY_PRICE_ID,
+ },
+ storage: {
+ monthly: env.STRIPE_PRO_STORAGE_MONTHLY_PRICE_ID,
+ yearly: env.STRIPE_PRO_STORAGE_YEARLY_PRICE_ID,
+ },
+ },
+}
diff --git a/packages/lib/api/storage.ts b/packages/lib/api/storage.ts
index 36abd83992f..0f7c3244d36 100644
--- a/packages/lib/api/storage.ts
+++ b/packages/lib/api/storage.ts
@@ -1,3 +1,4 @@
+import { env } from '@typebot.io/env'
import { config, Endpoint, S3 } from 'aws-sdk'
type GeneratePresignedUrlProps = {
@@ -14,34 +15,26 @@ export const generatePresignedUrl = ({
fileType,
sizeLimit = tenMB,
}: GeneratePresignedUrlProps): S3.PresignedPost => {
- if (
- !process.env.S3_ENDPOINT ||
- !process.env.S3_ACCESS_KEY ||
- !process.env.S3_SECRET_KEY
- )
+ if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
throw new Error(
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY'
)
- const sslEnabled =
- process.env.S3_SSL && process.env.S3_SSL === 'false' ? false : true
config.update({
- accessKeyId: process.env.S3_ACCESS_KEY,
- secretAccessKey: process.env.S3_SECRET_KEY,
- region: process.env.S3_REGION,
- sslEnabled,
+ accessKeyId: env.S3_ACCESS_KEY,
+ secretAccessKey: env.S3_SECRET_KEY,
+ region: env.S3_REGION,
+ sslEnabled: env.S3_SSL,
})
- const protocol = sslEnabled ? 'https' : 'http'
+ const protocol = env.S3_SSL ? 'https' : 'http'
const s3 = new S3({
endpoint: new Endpoint(
- `${protocol}://${process.env.S3_ENDPOINT}${
- process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''
- }`
+ `${protocol}://${env.S3_ENDPOINT}${env.S3_PORT ? `:${env.S3_PORT}` : ''}`
),
})
const presignedUrl = s3.createPresignedPost({
- Bucket: process.env.S3_BUCKET ?? 'typebot',
+ Bucket: env.S3_BUCKET ?? 'typebot',
Fields: {
key: filePath,
'Content-Type': fileType,
diff --git a/packages/lib/package.json b/packages/lib/package.json
index 72107fb341d..1fbc3d77212 100644
--- a/packages/lib/package.json
+++ b/packages/lib/package.json
@@ -13,10 +13,10 @@
"@typebot.io/tsconfig": "workspace:*",
"@types/nodemailer": "6.4.8",
"aws-sdk": "2.1415.0",
- "dotenv": "16.3.1",
"next": "13.4.3",
"nodemailer": "6.9.3",
- "typescript": "5.1.6"
+ "typescript": "5.1.6",
+ "@typebot.io/env": "workspace:*"
},
"peerDependencies": {
"aws-sdk": "2.1152.0",
diff --git a/packages/lib/playwright/baseConfig.ts b/packages/lib/playwright/baseConfig.ts
index 3a9f1f8dc96..4a6ea08efb1 100644
--- a/packages/lib/playwright/baseConfig.ts
+++ b/packages/lib/playwright/baseConfig.ts
@@ -1,24 +1,5 @@
import { PlaywrightTestConfig } from '@playwright/test'
import path from 'path'
-import fs from 'fs'
-
-const builderLocalEnvPath = path.join(
- __dirname,
- '../../../apps/builder/.env.local'
-)
-const localViewerEnvPath = path.join(
- __dirname,
- '../../../apps/viewer/.env.local'
-)
-if (fs.existsSync(builderLocalEnvPath))
- require('dotenv').config({
- path: builderLocalEnvPath,
- })
-
-if (fs.existsSync(localViewerEnvPath))
- require('dotenv').config({
- path: localViewerEnvPath,
- })
export const playwrightBaseConfig: PlaywrightTestConfig = {
globalSetup: require.resolve(path.join(__dirname, 'globalSetup')),
diff --git a/packages/lib/pricing.ts b/packages/lib/pricing.ts
index 91deac6ee0e..9cab9af0947 100644
--- a/packages/lib/pricing.ts
+++ b/packages/lib/pricing.ts
@@ -3,37 +3,6 @@ import { Plan } from '@typebot.io/prisma'
const infinity = -1
-export const priceIds = {
- [Plan.STARTER]: {
- base: {
- monthly: process.env.STRIPE_STARTER_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_STARTER_YEARLY_PRICE_ID,
- },
- chats: {
- monthly: process.env.STRIPE_STARTER_CHATS_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_STARTER_CHATS_YEARLY_PRICE_ID,
- },
- storage: {
- monthly: process.env.STRIPE_STARTER_STORAGE_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_STARTER_STORAGE_YEARLY_PRICE_ID,
- },
- },
- [Plan.PRO]: {
- base: {
- monthly: process.env.STRIPE_PRO_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_PRO_YEARLY_PRICE_ID,
- },
- chats: {
- monthly: process.env.STRIPE_PRO_CHATS_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_PRO_CHATS_YEARLY_PRICE_ID,
- },
- storage: {
- monthly: process.env.STRIPE_PRO_STORAGE_MONTHLY_PRICE_ID,
- yearly: process.env.STRIPE_PRO_STORAGE_YEARLY_PRICE_ID,
- },
- },
-}
-
export const prices = {
[Plan.STARTER]: 39,
[Plan.PRO]: 89,
diff --git a/packages/lib/telemetry/sendTelemetryEvent.ts b/packages/lib/telemetry/sendTelemetryEvent.ts
index 583d64a98dd..05de19d26f5 100644
--- a/packages/lib/telemetry/sendTelemetryEvent.ts
+++ b/packages/lib/telemetry/sendTelemetryEvent.ts
@@ -1,18 +1,18 @@
import got from 'got'
import { TelemetryEvent } from '@typebot.io/schemas/features/telemetry'
-import { isEmpty, isNotEmpty } from '../utils'
+import { isNotEmpty } from '../utils'
+import { env } from '@typebot.io/env'
export const sendTelemetryEvents = async (events: TelemetryEvent[]) => {
if (events.length === 0) return { message: 'No events to send' }
- if (isEmpty(process.env.TELEMETRY_WEBHOOK_URL))
- return { message: 'Telemetry not enabled' }
+ if (!env.TELEMETRY_WEBHOOK_URL) return { message: 'Telemetry not enabled' }
try {
- await got.post(process.env.TELEMETRY_WEBHOOK_URL, {
+ await got.post(env.TELEMETRY_WEBHOOK_URL, {
json: { events },
headers: {
- authorization: isNotEmpty(process.env.TELEMETRY_WEBHOOK_BEARER_TOKEN)
- ? `Bearer ${process.env.TELEMETRY_WEBHOOK_BEARER_TOKEN}`
+ authorization: env.TELEMETRY_WEBHOOK_BEARER_TOKEN
+ ? `Bearer ${env.TELEMETRY_WEBHOOK_BEARER_TOKEN}`
: undefined,
},
})
diff --git a/packages/lib/utils.ts b/packages/lib/utils.ts
index adade3949cc..8e516dac61c 100644
--- a/packages/lib/utils.ts
+++ b/packages/lib/utils.ts
@@ -19,6 +19,7 @@ import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/enu
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/enums'
import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/enums'
import { PictureChoiceBlock } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice'
+import { env } from '@typebot.io/env'
export const sendRequest = async (
params:
@@ -249,16 +250,6 @@ export const uploadFiles = async ({
declare const window: any
-export const env = (key = ''): string | undefined => {
- if (typeof window === 'undefined')
- return isEmpty(process.env['NEXT_PUBLIC_' + key])
- ? undefined
- : (process.env['NEXT_PUBLIC_' + key] as string)
-
- if (typeof window !== 'undefined' && window.__env)
- return isEmpty(window.__env[key]) ? undefined : window.__env[key]
-}
-
export const hasValue = (
value: string | undefined | null
): value is NonNullable =>
@@ -268,10 +259,8 @@ export const hasValue = (
value !== 'undefined' &&
value !== 'null'
-export const getViewerUrl = (props?: {
- returnAll?: boolean
-}): string | undefined =>
- props?.returnAll ? env('VIEWER_URL') : env('VIEWER_URL')?.split(',')[0]
+export const getViewerUrl = () =>
+ env.NEXT_PUBLIC_VIEWER_INTERNAL_URL ?? env.NEXT_PUBLIC_VIEWER_URL?.[0]
export const parseNumberWithCommas = (num: number) =>
num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
diff --git a/packages/prisma/.env.example b/packages/prisma/.env.example
deleted file mode 100644
index b6832edf33e..00000000000
--- a/packages/prisma/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
\ No newline at end of file
diff --git a/packages/prisma/package.json b/packages/prisma/package.json
index 53587ee986b..b384a98a9a3 100644
--- a/packages/prisma/package.json
+++ b/packages/prisma/package.json
@@ -6,11 +6,11 @@
"types": "./index.ts",
"private": true,
"scripts": {
- "dev": "tsx scripts/studio.ts",
- "db:generate": "tsx scripts/db-generate.ts",
- "db:push": "tsx scripts/db-push.ts",
- "migrate:deploy": "tsx scripts/migrate-deploy.ts",
- "migrate:dev": "prisma migrate dev --create-only --schema postgresql/schema.prisma",
+ "dev": "dotenv -e ./.env -e ../../.env -- tsx scripts/studio.ts",
+ "db:generate": "dotenv -e ./.env -e ../../.env -- tsx scripts/db-generate.ts",
+ "db:push": "dotenv -e ./.env -e ../../.env -- tsx scripts/db-push.ts",
+ "migrate:deploy": "dotenv -e ./.env -e ../../.env -- tsx scripts/migrate-deploy.ts",
+ "migrate:dev": "dotenv -e ./.env -e ../../.env -- prisma migrate dev --create-only --schema postgresql/schema.prisma",
"db:migrate": "pnpm migrate:deploy"
},
"dependencies": {
@@ -18,7 +18,7 @@
},
"devDependencies": {
"@types/node": "20.4.2",
- "dotenv": "16.3.1",
+ "dotenv-cli": "^7.2.1",
"prisma": "5.0.0",
"@typebot.io/tsconfig": "workspace:*",
"tsx": "3.12.7",
diff --git a/packages/prisma/scripts/executeCommand.ts b/packages/prisma/scripts/executeCommand.ts
index c912884231d..99008fa9934 100644
--- a/packages/prisma/scripts/executeCommand.ts
+++ b/packages/prisma/scripts/executeCommand.ts
@@ -1,11 +1,6 @@
import { exec } from 'child_process'
import { join, relative } from 'path'
-require('dotenv').config({
- override: true,
- path: join(__dirname, `../.env`),
-})
-
const postgesqlSchemaPath = relative(
process.cwd(),
join(__dirname, `../postgresql/schema.prisma`)
@@ -34,13 +29,13 @@ export const executePrismaCommand = (command: string, options?: Options) => {
executeCommand(`${command} --schema ${mysqlSchemaPath}`)
}
- if (databaseUrl?.startsWith('postgresql://')) {
+ if (databaseUrl?.startsWith('postgres')) {
console.log('Executing for PostgreSQL schema')
executeCommand(`${command} --schema ${postgesqlSchemaPath}`)
}
if (process.env.DATABASE_URL?.startsWith('postgres://')) {
- console.error('PostgreSQL `DATABASE_URL` should start with postgresql://')
+ console.error('PostgreSQL `DATABASE_URL` should start with postgres')
process.exit(1)
}
}
diff --git a/packages/prisma/scripts/migrate-deploy.ts b/packages/prisma/scripts/migrate-deploy.ts
index c7e8f3f71e6..f96b8733e64 100644
--- a/packages/prisma/scripts/migrate-deploy.ts
+++ b/packages/prisma/scripts/migrate-deploy.ts
@@ -1,4 +1,4 @@
import { executePrismaCommand } from './executeCommand'
-if (process.env.DATABASE_URL?.startsWith('postgresql://'))
+if (process.env.DATABASE_URL?.startsWith('postgres'))
executePrismaCommand('prisma migrate deploy')
diff --git a/packages/prisma/scripts/migrate-dev.ts b/packages/prisma/scripts/migrate-dev.ts
index 2016013f5e9..18dd6e36c4f 100644
--- a/packages/prisma/scripts/migrate-dev.ts
+++ b/packages/prisma/scripts/migrate-dev.ts
@@ -1,4 +1,4 @@
import { executePrismaCommand } from './executeCommand'
-if (process.env.DATABASE_URL?.startsWith('postgresql://'))
+if (process.env.DATABASE_URL?.startsWith('postgres'))
executePrismaCommand('prisma migrate dev --create-only')
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d088774f771..c2c4fbcc6ce 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -77,6 +77,9 @@ importers:
'@stripe/stripe-js':
specifier: 1.54.1
version: 1.54.1
+ '@t3-oss/env-nextjs':
+ specifier: ^0.6.0
+ version: 0.6.0(typescript@5.1.6)(zod@3.21.4)
'@tanstack/react-query':
specifier: ^4.29.19
version: 4.29.19(react-dom@18.2.0)(react@18.2.0)
@@ -98,6 +101,9 @@ importers:
'@typebot.io/emails':
specifier: workspace:*
version: link:../../packages/emails
+ '@typebot.io/env':
+ specifier: workspace:*
+ version: link:../../packages/env
'@typebot.io/nextjs':
specifier: workspace:*
version: link:../../packages/embeds/nextjs
@@ -230,6 +236,9 @@ importers:
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
+ sharp:
+ specifier: ^0.32.4
+ version: 0.32.4
slate:
specifier: 0.94.1
version: 0.94.1
@@ -318,15 +327,18 @@ importers:
'@types/tinycolor2':
specifier: 1.4.3
version: 1.4.3
- dotenv:
- specifier: 16.3.1
- version: 16.3.1
+ dotenv-cli:
+ specifier: ^7.2.1
+ version: 7.2.1
eslint:
specifier: 8.44.0
version: 8.44.0
eslint-config-custom:
specifier: workspace:*
version: link:../../packages/eslint-config-custom
+ next-runtime-env:
+ specifier: ^1.6.2
+ version: 1.6.2
superjson:
specifier: ^1.12.4
version: 1.12.4
@@ -388,6 +400,9 @@ importers:
'@types/react':
specifier: 18.0.28
version: 18.0.28
+ dotenv-cli:
+ specifier: ^7.2.1
+ version: 7.2.1
tsx:
specifier: 3.12.5
version: 3.12.5
@@ -424,9 +439,6 @@ importers:
'@typebot.io/schemas':
specifier: workspace:*
version: link:../../packages/schemas
- '@vercel/analytics':
- specifier: 1.0.1
- version: 1.0.1
aos:
specifier: 2.3.4
version: 2.3.4
@@ -473,6 +485,9 @@ importers:
cross-env:
specifier: 7.0.3
version: 7.0.3
+ dotenv-cli:
+ specifier: ^7.2.1
+ version: 7.2.1
eslint:
specifier: 8.44.0
version: 8.44.0
@@ -510,8 +525,8 @@ importers:
specifier: workspace:*
version: link:../../packages/prisma
ai:
- specifier: 2.2.8
- version: 2.2.8(react@18.2.0)(solid-js@1.7.8)(svelte@4.1.2)(vue@3.3.4)
+ specifier: 2.1.32
+ version: 2.1.32(react@18.2.0)(solid-js@1.7.8)(svelte@4.1.2)(vue@3.3.4)
aws-sdk:
specifier: 2.1415.0
version: 2.1415.0
@@ -579,6 +594,9 @@ importers:
'@typebot.io/emails':
specifier: workspace:*
version: link:../../packages/emails
+ '@typebot.io/env':
+ specifier: workspace:*
+ version: link:../../packages/env
'@typebot.io/lib':
specifier: workspace:*
version: link:../../packages/lib
@@ -609,9 +627,9 @@ importers:
'@types/sanitize-html':
specifier: 2.9.0
version: 2.9.0
- dotenv:
- specifier: 16.3.1
- version: 16.3.1
+ dotenv-cli:
+ specifier: ^7.2.1
+ version: 7.2.1
eslint:
specifier: 8.44.0
version: 8.44.0
@@ -621,6 +639,9 @@ importers:
google-auth-library:
specifier: 8.9.0
version: 8.9.0
+ next-runtime-env:
+ specifier: ^1.6.2
+ version: 1.6.2
node-fetch:
specifier: 3.3.1
version: 3.3.1
@@ -769,6 +790,9 @@ importers:
'@faire/mjml-react':
specifier: 3.3.0
version: 3.3.0(mjml@4.14.1)(react-dom@18.2.0)(react@18.2.0)
+ '@typebot.io/env':
+ specifier: workspace:*
+ version: link:../env
'@typebot.io/lib':
specifier: workspace:*
version: link:../lib
@@ -839,6 +863,9 @@ importers:
'@rollup/plugin-typescript':
specifier: 11.1.2
version: 11.1.2(rollup@3.26.2)(tslib@2.6.0)(typescript@5.1.6)
+ '@typebot.io/env':
+ specifier: workspace:*
+ version: link:../../env
'@typebot.io/lib':
specifier: workspace:*
version: link:../../lib
@@ -1039,6 +1066,25 @@ importers:
packages/embeds/wordpress: {}
+ packages/env:
+ dependencies:
+ '@t3-oss/env-nextjs':
+ specifier: ^0.6.0
+ version: 0.6.0(typescript@5.1.6)(zod@3.21.4)
+ zod:
+ specifier: 3.21.4
+ version: 3.21.4
+ devDependencies:
+ '@typebot.io/tsconfig':
+ specifier: workspace:*
+ version: link:../tsconfig
+ '@types/node':
+ specifier: ^20.4.9
+ version: 20.4.9
+ esbuild:
+ specifier: ^0.19.1
+ version: 0.19.1
+
packages/eslint-config-custom:
dependencies:
eslint:
@@ -1076,6 +1122,9 @@ importers:
'@playwright/test':
specifier: 1.36.0
version: 1.36.0
+ '@typebot.io/env':
+ specifier: workspace:*
+ version: link:../env
'@typebot.io/prisma':
specifier: workspace:*
version: link:../prisma
@@ -1091,9 +1140,6 @@ importers:
aws-sdk:
specifier: 2.1415.0
version: 2.1415.0
- dotenv:
- specifier: 16.3.1
- version: 16.3.1
next:
specifier: 13.4.3
version: 13.4.3(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0)
@@ -1116,9 +1162,9 @@ importers:
'@types/node':
specifier: 20.4.2
version: 20.4.2
- dotenv:
- specifier: 16.3.1
- version: 16.3.1
+ dotenv-cli:
+ specifier: ^7.2.1
+ version: 7.2.1
prisma:
specifier: 5.0.0
version: 5.0.0
@@ -6898,6 +6944,15 @@ packages:
dev: true
optional: true
+ /@esbuild/android-arm64@0.19.1:
+ resolution: {integrity: sha512-CqhrKvDSt76I0so/5afqgKrMv41FjbfUKFrcZddMnrZKqJU70I1MWLVJrImJuYMaY4Yb9rn4UKfF7oZ0BOleVw==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/android-arm@0.15.18:
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
engines: {node: '>=12'}
@@ -6924,6 +6979,15 @@ packages:
dev: true
optional: true
+ /@esbuild/android-arm@0.19.1:
+ resolution: {integrity: sha512-yjTucwcOua52z14RL30JMwmCdylsQ5WrErGkAb6VL0MWPbnwJyLejydaRcUqkPO6g0MowlzavdxrR7AcfCW+yA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/android-x64@0.17.19:
resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==}
engines: {node: '>=12'}
@@ -6941,6 +7005,15 @@ packages:
dev: true
optional: true
+ /@esbuild/android-x64@0.19.1:
+ resolution: {integrity: sha512-VA29h01MrPkymIL1bFtvL2L4WPogiMGW2N/M+vXZHHOv6LgA9vjzVskTt0v5LjeCjx1PFDcR0ASKy8Y7Gm+iIA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/darwin-arm64@0.17.19:
resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==}
engines: {node: '>=12'}
@@ -6958,6 +7031,15 @@ packages:
dev: true
optional: true
+ /@esbuild/darwin-arm64@0.19.1:
+ resolution: {integrity: sha512-Be4Cf6WDH7QkLHEpfzQOlBOFdqmqYTSqw2yG3SVmzB3++wy3K7wiNGedezL+q6Jb4weqT9tchO5kkLDC08Jnzg==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/darwin-x64@0.17.19:
resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==}
engines: {node: '>=12'}
@@ -6975,6 +7057,15 @@ packages:
dev: true
optional: true
+ /@esbuild/darwin-x64@0.19.1:
+ resolution: {integrity: sha512-SewtenJi6zCEfZRSUchb+LgJ/IQw8QvnKECPu/qHII1fLQKnVPUVR+VH2IuS03DD9WWnAi3yfOvBNwtrp3WXtg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/freebsd-arm64@0.17.19:
resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==}
engines: {node: '>=12'}
@@ -6992,6 +7083,15 @@ packages:
dev: true
optional: true
+ /@esbuild/freebsd-arm64@0.19.1:
+ resolution: {integrity: sha512-TadKO0AaTDAPV2RyGZQ0AaiDTVYg7RsgNaA6OJjXXmoLbTs++NwHtzAmVFBq8Q/P9A11wgkv36HeyAYhWHbW1w==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/freebsd-x64@0.17.19:
resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==}
engines: {node: '>=12'}
@@ -7009,6 +7109,15 @@ packages:
dev: true
optional: true
+ /@esbuild/freebsd-x64@0.19.1:
+ resolution: {integrity: sha512-DrFMGLF0/aAcZgwhtZr1cby7aHlalpFjLCe5CiI8mm0Kqhhc8gyNZKreaZzvir8CQe0H17p9xx6M9ben5R3r0g==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-arm64@0.17.19:
resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==}
engines: {node: '>=12'}
@@ -7026,6 +7135,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-arm64@0.19.1:
+ resolution: {integrity: sha512-6ku/R2EzsdjyBaqQn+xGOPbv+BBYBXQYzlA04/46YQLmXkdApi0GYyUwiCXYBxm578iyywzGmM0rep1/q8tuFQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-arm@0.17.19:
resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==}
engines: {node: '>=12'}
@@ -7043,6 +7161,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-arm@0.19.1:
+ resolution: {integrity: sha512-lCWDVPpQO/Dt5MEqctKujgtUVmwQx7J2Q83EqX/9BejN7BIX4fGJ0QKMiIyy21PFh+/64ArN+Ovh1tzYkTt2wg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-ia32@0.17.19:
resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==}
engines: {node: '>=12'}
@@ -7060,6 +7187,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-ia32@0.19.1:
+ resolution: {integrity: sha512-8AKFBk9v/zBDsADvK/0BWZUxkjEc0QDwO8rvbHJKqAZx6DF/VSeBxTRmqWeecrJmx+n3kemEwML9z0eD9IHweQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-loong64@0.15.18:
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
@@ -7086,6 +7222,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-loong64@0.19.1:
+ resolution: {integrity: sha512-6mOS5CxTGD8qOymp2y4KoM4ir+/REgjdJQFYpwP+WqjrWBo+PUevDGeHHjzCdw/R19PkFqS1bRzv8cTCmB/5kA==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-mips64el@0.17.19:
resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==}
engines: {node: '>=12'}
@@ -7103,6 +7248,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-mips64el@0.19.1:
+ resolution: {integrity: sha512-Bzmv6rRMzR4ErG2k/jwfj5jKNzVMVEI1tThuirFdAoE+duUv+jlDnlwxsN3s1eqMzADTOV2sSIcUUOfgv++Dgg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-ppc64@0.17.19:
resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==}
engines: {node: '>=12'}
@@ -7120,6 +7274,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-ppc64@0.19.1:
+ resolution: {integrity: sha512-mPOxA7bd3nmx8TkuO/9M/tE0fnvmuX0wlpwnTL6DPLgkb/Z/KkupexSIw4cLfznn/fPzD89y17VWBjlVNyrpCQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-riscv64@0.17.19:
resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==}
engines: {node: '>=12'}
@@ -7137,6 +7300,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-riscv64@0.19.1:
+ resolution: {integrity: sha512-znYb2Mhe9xKIDeIYuTD6vCcUltvYzRT5Yq6sVcdhPrGu8DRdsNZS04B2tSeM+j7T03jL4yY+7/G/jxSJJ9LX2A==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-s390x@0.17.19:
resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==}
engines: {node: '>=12'}
@@ -7154,6 +7326,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-s390x@0.19.1:
+ resolution: {integrity: sha512-BBIE32cyqAYhMOQ42/jnecoF5P/S5lMob2vXSUiFpD3xCFbXOFkjP1OjfFKnalSO9+B5emvPTQFfNQXuLeVGEw==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/linux-x64@0.17.19:
resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==}
engines: {node: '>=12'}
@@ -7171,6 +7352,15 @@ packages:
dev: true
optional: true
+ /@esbuild/linux-x64@0.19.1:
+ resolution: {integrity: sha512-PoCvKdHTIbnHmVJ5OEdewGMSw40HDFRTrC/imwh8vrp695RbSUpOqBqNBT45neK0FQleGFbSE/A9X6HlXPDhqA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/netbsd-x64@0.17.19:
resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==}
engines: {node: '>=12'}
@@ -7188,6 +7378,15 @@ packages:
dev: true
optional: true
+ /@esbuild/netbsd-x64@0.19.1:
+ resolution: {integrity: sha512-4OrGMPorHCq9h52VLtyyyAmPjC2ZlANx54VDYyCrqXUOi+k0qxnPKXKKprVES67w2mE7TZJx9qZmT+jHeiZbHQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/openbsd-x64@0.17.19:
resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==}
engines: {node: '>=12'}
@@ -7205,6 +7404,15 @@ packages:
dev: true
optional: true
+ /@esbuild/openbsd-x64@0.19.1:
+ resolution: {integrity: sha512-3a7ZYMjBC4P3FKdTmUZHJw7Mhzp71m+iSFFhX1PnLZ03qmyaB2K+vJZCk4PjRjAvm5lSupJQQtM/AFMyLgKlxQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/sunos-x64@0.17.19:
resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==}
engines: {node: '>=12'}
@@ -7222,6 +7430,15 @@ packages:
dev: true
optional: true
+ /@esbuild/sunos-x64@0.19.1:
+ resolution: {integrity: sha512-29yWBN5XfEjXT8yoeVb8cXfN1jAQLB+uskog1vBMhFR+YWOYvsrwPnh4hspETC/JnF95J+iETrvxgOUlICTWIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/win32-arm64@0.17.19:
resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==}
engines: {node: '>=12'}
@@ -7239,6 +7456,15 @@ packages:
dev: true
optional: true
+ /@esbuild/win32-arm64@0.19.1:
+ resolution: {integrity: sha512-9Hb/WUXgyXlL55w3iNVyLkN9gq9x+agv3kk80foWbfpOwe7Qw4Vx6JGB+XQdsIfvvP1kShVQPIvBgVj0TxLlVw==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/win32-ia32@0.17.19:
resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==}
engines: {node: '>=12'}
@@ -7256,6 +7482,15 @@ packages:
dev: true
optional: true
+ /@esbuild/win32-ia32@0.19.1:
+ resolution: {integrity: sha512-VGdtEcXX/f01NgoM8emDnpdOyrZCQ7VTwLv89MOl3mvJ5fbCOBMNCa8t7RZS4lf12RS87qOuJFX7Bh9aLTbSxg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@esbuild/win32-x64@0.17.19:
resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==}
engines: {node: '>=12'}
@@ -7273,6 +7508,15 @@ packages:
dev: true
optional: true
+ /@esbuild/win32-x64@0.19.1:
+ resolution: {integrity: sha512-H6u8OHmJkKJubLbukVOyi9yA5lzK8VE4TFEkZj2vgusTUPvFeMQ8YnWviVc9F6PuKS6ZIpOvi2/sfiW8tQZQ2g==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
/@eslint-community/eslint-utils@4.4.0(eslint@8.44.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7508,7 +7752,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
jest-message-util: 29.5.0
jest-util: 29.5.0
@@ -7529,14 +7773,14 @@ packages:
'@jest/test-result': 29.5.0
'@jest/transform': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
ansi-escapes: 4.3.2
chalk: 4.1.2
ci-info: 3.8.0
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.5.0
- jest-config: 29.5.0(@types/node@20.4.2)
+ jest-config: 29.5.0(@types/node@20.5.6)
jest-haste-map: 29.5.0
jest-message-util: 29.5.0
jest-regex-util: 29.4.3
@@ -7563,7 +7807,7 @@ packages:
dependencies:
'@jest/fake-timers': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
jest-mock: 29.5.0
dev: true
@@ -7590,7 +7834,7 @@ packages:
dependencies:
'@jest/types': 29.5.0
'@sinonjs/fake-timers': 10.2.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
jest-message-util: 29.5.0
jest-mock: 29.5.0
jest-util: 29.5.0
@@ -7623,7 +7867,7 @@ packages:
'@jest/transform': 29.5.0
'@jest/types': 29.5.0
'@jridgewell/trace-mapping': 0.3.18
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
collect-v8-coverage: 1.0.1
exit: 0.1.2
@@ -7710,7 +7954,7 @@ packages:
'@jest/schemas': 29.4.3
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
'@types/yargs': 17.0.24
chalk: 4.1.2
@@ -9340,6 +9584,27 @@ packages:
dependencies:
defer-to-connect: 2.0.1
+ /@t3-oss/env-core@0.6.0(typescript@5.1.6)(zod@3.21.4):
+ resolution: {integrity: sha512-3FkPAba069WRZVVab/sB1m3eSGn/rZeypx5k+sWEu1d+k0OQdRDnvFS+7MtxYgqVrwaRk3b7yVnX2dgSPVmWPQ==}
+ peerDependencies:
+ typescript: '>=4.7.2'
+ zod: ^3.0.0
+ dependencies:
+ typescript: 5.1.6
+ zod: 3.21.4
+ dev: false
+
+ /@t3-oss/env-nextjs@0.6.0(typescript@5.1.6)(zod@3.21.4):
+ resolution: {integrity: sha512-SpzcGNIbUYcQw4zPPFeRJqCC1560zL7QmB0puIqOnuCsmykPkqHPX+n9CNZLXVQerboHzfvb7Kd+jAdouk72Vw==}
+ peerDependencies:
+ typescript: '>=4.7.2'
+ zod: ^3.0.0
+ dependencies:
+ '@t3-oss/env-core': 0.6.0(typescript@5.1.6)(zod@3.21.4)
+ typescript: 5.1.6
+ zod: 3.21.4
+ dev: false
+
/@tanstack/query-core@4.29.19:
resolution: {integrity: sha512-uPe1DukeIpIHpQi6UzIgBcXsjjsDaLnc7hF+zLBKnaUlh7jFE/A+P8t4cU4VzKPMFB/C970n/9SxtpO5hmIRgw==}
dev: false
@@ -9588,13 +9853,13 @@ packages:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.35
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/bonjour@3.5.10:
resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/canvas-confetti@1.6.0:
@@ -9605,13 +9870,13 @@ packages:
resolution: {integrity: sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==}
dependencies:
'@types/express-serve-static-core': 4.17.35
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/connect@3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/content-type@1.1.5:
@@ -9645,7 +9910,7 @@ packages:
/@types/express-serve-static-core@4.17.35:
resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
'@types/send': 0.17.1
@@ -9663,7 +9928,7 @@ packages:
/@types/graceful-fs@4.1.6:
resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: true
/@types/hast@2.3.4:
@@ -9692,7 +9957,7 @@ packages:
/@types/http-proxy@1.17.11:
resolution: {integrity: sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/is-hotkey@0.1.7:
@@ -9726,7 +9991,7 @@ packages:
/@types/jsdom@20.0.1:
resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
'@types/tough-cookie': 4.0.2
parse5: 7.1.2
dev: true
@@ -9747,7 +10012,7 @@ packages:
/@types/keyv@3.1.4:
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/lodash.mergewith@4.6.7:
@@ -9775,7 +10040,7 @@ packages:
/@types/micro@7.3.7:
resolution: {integrity: sha512-MFsX7eCj0Tg3TtphOQvANNvNtFpya+s/rYOCdV6o+DFjOQPFi2EVRbBALjbbgZTXUaJP1Q281MJiJOD40d0UxQ==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: true
/@types/mime@1.3.2:
@@ -9793,23 +10058,24 @@ packages:
minio: 7.1.1
dev: true
- /@types/node-fetch@2.6.4:
- resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
- dependencies:
- '@types/node': 20.4.2
- form-data: 3.0.1
- dev: false
-
/@types/node@17.0.45:
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
dev: false
/@types/node@18.11.18:
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
+ dev: true
/@types/node@20.4.2:
resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==}
+ /@types/node@20.4.9:
+ resolution: {integrity: sha512-8e2HYcg7ohnTUbHk8focoklEQYvemQmu9M/f43DZVx43kHn0tE3BY/6gSDxS7k0SprtS0NHvj+L80cGLnoOUcQ==}
+ dev: true
+
+ /@types/node@20.5.6:
+ resolution: {integrity: sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==}
+
/@types/nodemailer@6.4.8:
resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==}
dependencies:
@@ -9845,7 +10111,7 @@ packages:
/@types/prompts@2.4.4:
resolution: {integrity: sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
kleur: 3.0.3
dev: true
@@ -9938,7 +10204,7 @@ packages:
/@types/responselike@1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/retry@0.12.0:
@@ -9954,7 +10220,7 @@ packages:
/@types/sax@1.2.4:
resolution: {integrity: sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/scheduler@0.16.3:
@@ -9968,7 +10234,7 @@ packages:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies:
'@types/mime': 1.3.2
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/serve-index@1.9.1:
@@ -9981,13 +10247,13 @@ packages:
resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==}
dependencies:
'@types/mime': 3.0.1
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/sockjs@0.3.33:
resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/stack-utils@2.0.1:
@@ -10009,7 +10275,7 @@ packages:
/@types/ws@8.5.4:
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
dev: false
/@types/yargs-parser@21.0.0:
@@ -11066,10 +11332,6 @@ packages:
react: 18.2.0
dev: false
- /@vercel/analytics@1.0.1:
- resolution: {integrity: sha512-Ux0c9qUfkcPqng3vrR0GTrlQdqNJ2JREn/2ydrVuKwM3RtMfF2mWX31Ijqo1opSjNAq6rK76PwtANw6kl6TAow==}
- dev: false
-
/@vitejs/plugin-react@3.1.0(vite@4.3.9):
resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -11290,13 +11552,6 @@ packages:
/abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
- /abort-controller@3.0.0:
- resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
- engines: {node: '>=6.5'}
- dependencies:
- event-target-shim: 5.0.1
- dev: false
-
/accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@@ -11380,13 +11635,6 @@ packages:
transitivePeerDependencies:
- supports-color
- /agentkeepalive@4.5.0:
- resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==}
- engines: {node: '>= 8.0.0'}
- dependencies:
- humanize-ms: 1.2.1
- dev: false
-
/aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@@ -11395,8 +11643,8 @@ packages:
indent-string: 4.0.0
dev: false
- /ai@2.2.8(react@18.2.0)(solid-js@1.7.8)(svelte@4.1.2)(vue@3.3.4):
- resolution: {integrity: sha512-DzMqqXnKqcVlngznYwfyU/Z8ljpiaXCXlKVhkEVOkEpVEHN8K9eWgldhG7IavyFQjEpC+R2rnkXLEsrxV+yXcw==}
+ /ai@2.1.32(react@18.2.0)(solid-js@1.7.8)(svelte@4.1.2)(vue@3.3.4):
+ resolution: {integrity: sha512-G+mk7OfSxVR5s2cmpni89olZjXo5XbxPzzG8DAZThoJA2725hczfvO/gqLYGUToq92vzr0XgCHP6JJFK9so5fg==}
engines: {node: '>=14.6'}
peerDependencies:
react: ^18.2.0
@@ -11415,7 +11663,6 @@ packages:
dependencies:
eventsource-parser: 1.0.0
nanoid: 3.3.6
- openai: 4.0.0
react: 18.2.0
solid-js: 1.7.8
solid-swr-store: 0.10.7(solid-js@1.7.8)(swr-store@0.10.6)
@@ -11425,8 +11672,6 @@ packages:
swr-store: 0.10.6
swrv: 1.0.4(vue@3.3.4)
vue: 3.3.4
- transitivePeerDependencies:
- - encoding
dev: false
/ajv-formats@2.1.1(ajv@8.12.0):
@@ -11855,6 +12100,10 @@ packages:
dequal: 2.0.3
dev: false
+ /b4a@1.6.4:
+ resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
+ dev: false
+
/babel-jest@29.5.0(@babel/core@7.22.9):
resolution: {integrity: sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -12114,10 +12363,6 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- /base-64@0.1.0:
- resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==}
- dev: false
-
/base16@1.0.0:
resolution: {integrity: sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==}
dev: false
@@ -12152,6 +12397,14 @@ packages:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
+ /bl@4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: false
+
/block-stream2@2.1.0:
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
dependencies:
@@ -12313,6 +12566,13 @@ packages:
ieee754: 1.2.1
isarray: 1.0.0
+ /buffer@5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: false
+
/buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
dependencies:
@@ -12512,10 +12772,6 @@ packages:
resolution: {integrity: sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==}
dev: true
- /charenc@0.0.2:
- resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
- dev: false
-
/charset@1.0.1:
resolution: {integrity: sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==}
engines: {node: '>=4.0.0'}
@@ -12557,6 +12813,10 @@ packages:
optionalDependencies:
fsevents: 2.3.2
+ /chownr@1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ dev: false
+
/chrome-trace-event@1.0.3:
resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
engines: {node: '>=6.0'}
@@ -12764,10 +13024,25 @@ packages:
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ /color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+ dev: false
+
/color2k@2.0.2:
resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==}
dev: false
+ /color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+ dev: false
+
/colord@2.9.3:
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
@@ -13107,10 +13382,6 @@ packages:
shebang-command: 2.0.0
which: 2.0.2
- /crypt@0.0.2:
- resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
- dev: false
-
/crypto-js@4.1.1:
resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==}
dev: false
@@ -13688,6 +13959,11 @@ packages:
repeat-string: 1.6.1
dev: false
+ /detect-libc@2.0.2:
+ resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
+ engines: {node: '>=8'}
+ dev: false
+
/detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
@@ -13750,13 +14026,6 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dev: true
- /digest-fetch@1.3.0:
- resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
- dependencies:
- base-64: 0.1.0
- md5: 2.3.0
- dev: false
-
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -13907,6 +14176,21 @@ packages:
is-obj: 2.0.0
dev: false
+ /dotenv-cli@7.2.1:
+ resolution: {integrity: sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==}
+ hasBin: true
+ dependencies:
+ cross-spawn: 7.0.3
+ dotenv: 16.3.1
+ dotenv-expand: 10.0.0
+ minimist: 1.2.8
+ dev: true
+
+ /dotenv-expand@10.0.0:
+ resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
+ engines: {node: '>=12'}
+ dev: true
+
/dotenv@16.3.1:
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
engines: {node: '>=12'}
@@ -14366,6 +14650,36 @@ packages:
'@esbuild/win32-x64': 0.17.5
dev: true
+ /esbuild@0.19.1:
+ resolution: {integrity: sha512-IknHHwV4B/H4imOAu+416fuCvPfRjdncoyGi7eunhSvHuHkdNs50sLWan2LEG2Mym07TuW6gJUIyRS9G1miHEg==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/android-arm': 0.19.1
+ '@esbuild/android-arm64': 0.19.1
+ '@esbuild/android-x64': 0.19.1
+ '@esbuild/darwin-arm64': 0.19.1
+ '@esbuild/darwin-x64': 0.19.1
+ '@esbuild/freebsd-arm64': 0.19.1
+ '@esbuild/freebsd-x64': 0.19.1
+ '@esbuild/linux-arm': 0.19.1
+ '@esbuild/linux-arm64': 0.19.1
+ '@esbuild/linux-ia32': 0.19.1
+ '@esbuild/linux-loong64': 0.19.1
+ '@esbuild/linux-mips64el': 0.19.1
+ '@esbuild/linux-ppc64': 0.19.1
+ '@esbuild/linux-riscv64': 0.19.1
+ '@esbuild/linux-s390x': 0.19.1
+ '@esbuild/linux-x64': 0.19.1
+ '@esbuild/netbsd-x64': 0.19.1
+ '@esbuild/openbsd-x64': 0.19.1
+ '@esbuild/sunos-x64': 0.19.1
+ '@esbuild/win32-arm64': 0.19.1
+ '@esbuild/win32-ia32': 0.19.1
+ '@esbuild/win32-x64': 0.19.1
+ dev: true
+
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
@@ -14561,7 +14875,7 @@ packages:
minimatch: 3.1.2
object.values: 1.1.6
resolve: 1.22.2
- semver: 6.3.0
+ semver: 6.3.1
tsconfig-paths: 3.14.2
transitivePeerDependencies:
- eslint-import-resolver-typescript
@@ -14591,7 +14905,7 @@ packages:
minimatch: 3.1.2
object.entries: 1.1.6
object.fromentries: 2.0.6
- semver: 6.3.0
+ semver: 6.3.1
dev: false
/eslint-plugin-react-hooks@5.0.0-canary-7118f5dd7-20230705(eslint@8.44.0):
@@ -14846,15 +15160,10 @@ packages:
resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==}
engines: {node: '>= 0.8'}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
require-like: 0.1.2
dev: false
- /event-target-shim@5.0.1:
- resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
- engines: {node: '>=6'}
- dev: false
-
/eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
@@ -14916,6 +15225,11 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
+ /expand-template@2.0.3:
+ resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
+ engines: {node: '>=6'}
+ dev: false
+
/expect@29.5.0:
resolution: {integrity: sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -14996,6 +15310,10 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ /fast-fifo@1.3.2:
+ resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
+ dev: false
+
/fast-glob@3.2.12:
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
engines: {node: '>=8.6.0'}
@@ -15278,23 +15596,10 @@ packages:
webpack: 5.76.1
dev: false
- /form-data-encoder@1.7.2:
- resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
- dev: false
-
/form-data-encoder@2.1.4:
resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
engines: {node: '>= 14.17'}
- /form-data@3.0.1:
- resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
- engines: {node: '>= 6'}
- dependencies:
- asynckit: 0.4.0
- combined-stream: 1.0.8
- mime-types: 2.1.35
- dev: false
-
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@@ -15303,14 +15608,6 @@ packages:
combined-stream: 1.0.8
mime-types: 2.1.35
- /formdata-node@4.4.1:
- resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
- engines: {node: '>= 12.20'}
- dependencies:
- node-domexception: 1.0.0
- web-streams-polyfill: 4.0.0-beta.3
- dev: false
-
/formdata-polyfill@4.0.10:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -15382,6 +15679,10 @@ packages:
engines: {node: '>= 0.6'}
dev: false
+ /fs-constants@1.0.0:
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+ dev: false
+
/fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@@ -15531,6 +15832,10 @@ packages:
/get-tsconfig@4.5.0:
resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==}
+ /github-from-package@0.0.0:
+ resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+ dev: false
+
/github-slugger@1.5.0:
resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==}
dev: false
@@ -16224,12 +16529,6 @@ packages:
engines: {node: '>=14.18.0'}
dev: false
- /humanize-ms@1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
- dependencies:
- ms: 2.1.3
- dev: false
-
/husky@8.0.3:
resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
engines: {node: '>=14'}
@@ -16518,6 +16817,10 @@ packages:
/is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+ /is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+ dev: false
+
/is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
dependencies:
@@ -16536,10 +16839,6 @@ packages:
call-bind: 1.0.2
has-tostringtag: 1.0.0
- /is-buffer@1.1.6:
- resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
- dev: false
-
/is-buffer@2.0.5:
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
engines: {node: '>=4'}
@@ -16929,7 +17228,7 @@ packages:
'@jest/expect': 29.5.0
'@jest/test-result': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
co: 4.6.0
dedent: 0.7.0
@@ -16966,7 +17265,7 @@ packages:
exit: 0.1.2
graceful-fs: 4.2.11
import-local: 3.1.0
- jest-config: 29.5.0(@types/node@20.4.2)
+ jest-config: 29.5.0(@types/node@20.5.6)
jest-util: 29.5.0
jest-validate: 29.5.0
prompts: 2.4.2
@@ -16977,7 +17276,7 @@ packages:
- ts-node
dev: true
- /jest-config@29.5.0(@types/node@20.4.2):
+ /jest-config@29.5.0(@types/node@20.5.6):
resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
peerDependencies:
@@ -16992,7 +17291,7 @@ packages:
'@babel/core': 7.22.9
'@jest/test-sequencer': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
babel-jest: 29.5.0(@babel/core@7.22.9)
chalk: 4.1.2
ci-info: 3.8.0
@@ -17074,7 +17373,7 @@ packages:
'@jest/environment': 29.5.0
'@jest/fake-timers': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
jest-mock: 29.5.0
jest-util: 29.5.0
dev: true
@@ -17090,7 +17389,7 @@ packages:
dependencies:
'@jest/types': 29.5.0
'@types/graceful-fs': 4.1.6
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
anymatch: 3.1.3
fb-watchman: 2.0.2
graceful-fs: 4.2.11
@@ -17141,7 +17440,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
jest-util: 29.5.0
dev: true
@@ -17196,7 +17495,7 @@ packages:
'@jest/test-result': 29.5.0
'@jest/transform': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
emittery: 0.13.1
graceful-fs: 4.2.11
@@ -17227,7 +17526,7 @@ packages:
'@jest/test-result': 29.5.0
'@jest/transform': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
cjs-module-lexer: 1.2.2
collect-v8-coverage: 1.0.1
@@ -17282,7 +17581,7 @@ packages:
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
chalk: 4.1.2
ci-info: 3.8.0
graceful-fs: 4.2.11
@@ -17306,7 +17605,7 @@ packages:
dependencies:
'@jest/test-result': 29.5.0
'@jest/types': 29.5.0
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
ansi-escapes: 4.3.2
chalk: 4.1.2
emittery: 0.13.1
@@ -17318,7 +17617,7 @@ packages:
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -17326,7 +17625,7 @@ packages:
resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
- '@types/node': 20.4.2
+ '@types/node': 20.5.6
jest-util: 29.5.0
merge-stream: 2.0.0
supports-color: 8.1.1
@@ -17958,14 +18257,6 @@ packages:
hasBin: true
dev: false
- /md5@2.3.0:
- resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
- dependencies:
- charenc: 0.0.2
- crypt: 0.0.2
- is-buffer: 1.1.6
- dev: false
-
/mdast-squeeze-paragraphs@4.0.0:
resolution: {integrity: sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==}
dependencies:
@@ -18532,6 +18823,10 @@ packages:
transitivePeerDependencies:
- encoding
+ /mkdirp-classic@0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ dev: false
+
/mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
@@ -18599,6 +18894,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ /napi-build-utils@1.0.2:
+ resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
+ dev: false
+
/native-promise-only@0.8.1:
resolution: {integrity: sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==}
dev: false
@@ -18657,6 +18956,12 @@ packages:
server-only: 0.0.1
dev: false
+ /next-runtime-env@1.6.2:
+ resolution: {integrity: sha512-JETzGBe4v1gjb3dbu3unZ/kUPEOgtyz+R5YJNTfdVpWFK8YotyM9sitj1/NPNZ7knjmLDVrljnwvamjBT7UALQ==}
+ dependencies:
+ chalk: 4.1.2
+ dev: true
+
/next-transpile-modules@10.0.0:
resolution: {integrity: sha512-FyeJ++Lm2Fq31gbThiRCrJlYpIY9QaI7A3TjuhQLzOix8ChQrvn5ny4MhfIthS5cy6+uK1AhDRvxVdW17y3Xdw==}
dependencies:
@@ -18771,9 +19076,21 @@ packages:
tslib: 2.6.0
dev: false
+ /node-abi@3.47.0:
+ resolution: {integrity: sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.5.4
+ dev: false
+
+ /node-addon-api@6.1.0:
+ resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
+ dev: false
+
/node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
+ dev: true
/node-emoji@1.11.0:
resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==}
@@ -19094,22 +19411,6 @@ packages:
- debug
dev: false
- /openai@4.0.0:
- resolution: {integrity: sha512-UHv70gIw20pxu9tiUueE9iS+4U4eTGiTgQr+zlJ5aX4oj6LUUp+7mBn0xAqilawftwUB/biohPth2vcZFmoNYw==}
- hasBin: true
- dependencies:
- '@types/node': 18.11.18
- '@types/node-fetch': 2.6.4
- abort-controller: 3.0.0
- agentkeepalive: 4.5.0
- digest-fetch: 1.3.0
- form-data-encoder: 1.7.2
- formdata-node: 4.4.1
- node-fetch: 2.6.11
- transitivePeerDependencies:
- - encoding
- dev: false
-
/openapi-to-postmanv2@1.2.7:
resolution: {integrity: sha512-oG3PZfAAljy5ebot8DZGLFDNNmDZ/qWqI/dboWlgg5hRj6dSSrXeiyXL6VQpcGDalxVX4jSChufOq2eDsFXp4w==}
engines: {node: '>=4'}
@@ -20422,6 +20723,25 @@ packages:
resolution: {integrity: sha512-qs2ansoQEwzNiV5eAcRT1p1EC/dmEzaATVDJNiB3g2sRDWdA7b7MurXdJjB2+/WQktGWZwxvDrnuRFbWuIr64g==}
dev: false
+ /prebuild-install@7.1.1:
+ resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ detect-libc: 2.0.2
+ expand-template: 2.0.3
+ github-from-package: 0.0.0
+ minimist: 1.2.8
+ mkdirp-classic: 0.5.3
+ napi-build-utils: 1.0.2
+ node-abi: 3.47.0
+ pump: 3.0.0
+ rc: 1.2.8
+ simple-get: 4.0.1
+ tar-fs: 2.1.1
+ tunnel-agent: 0.6.0
+ dev: false
+
/prelude-ls@1.1.2:
resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
engines: {node: '>= 0.8.0'}
@@ -20660,6 +20980,10 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ /queue-tick@1.0.1:
+ resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
+ dev: false
+
/queue@6.0.2:
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
dependencies:
@@ -21866,6 +22190,14 @@ packages:
dependencies:
lru-cache: 6.0.0
+ /semver@7.5.4:
+ resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: false
+
/send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'}
@@ -21975,6 +22307,21 @@ packages:
/shallowequal@1.1.0:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
+ /sharp@0.32.4:
+ resolution: {integrity: sha512-exUnZewqVZC6UXqXuQ8fyJJv0M968feBi04jb9GcUHrWtkRoAKnbJt8IfwT4NJs7FskArbJ14JAFGVuooszoGg==}
+ engines: {node: '>=14.15.0'}
+ requiresBuild: true
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.2
+ node-addon-api: 6.1.0
+ prebuild-install: 7.1.1
+ semver: 7.5.4
+ simple-get: 4.0.1
+ tar-fs: 3.0.4
+ tunnel-agent: 0.6.0
+ dev: false
+
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -22011,6 +22358,24 @@ packages:
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ /simple-concat@1.0.1:
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+ dev: false
+
+ /simple-get@4.0.1:
+ resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
+ dependencies:
+ decompress-response: 6.0.0
+ once: 1.4.0
+ simple-concat: 1.0.1
+ dev: false
+
+ /simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ dependencies:
+ is-arrayish: 0.3.2
+ dev: false
+
/sirv@1.0.19:
resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==}
engines: {node: '>= 10'}
@@ -22346,6 +22711,13 @@ packages:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
+ /streamx@2.15.1:
+ resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==}
+ dependencies:
+ fast-fifo: 1.3.2
+ queue-tick: 1.0.1
+ dev: false
+
/strict-uri-encode@2.0.0:
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
engines: {node: '>=4'}
@@ -22816,6 +23188,42 @@ packages:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
+ /tar-fs@2.1.1:
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+ dev: false
+
+ /tar-fs@3.0.4:
+ resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
+ dependencies:
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 3.1.6
+ dev: false
+
+ /tar-stream@2.2.0:
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ bl: 4.1.0
+ end-of-stream: 1.4.4
+ fs-constants: 1.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: false
+
+ /tar-stream@3.1.6:
+ resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
+ dependencies:
+ b4a: 1.6.4
+ fast-fifo: 1.3.2
+ streamx: 2.15.1
+ dev: false
+
/terser-webpack-plugin@5.3.9(webpack@5.76.1):
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
engines: {node: '>= 10.13.0'}
@@ -23218,6 +23626,12 @@ packages:
fsevents: 2.3.2
dev: true
+ /tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
/turbo-darwin-64@1.10.12:
resolution: {integrity: sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==}
cpu: [x64]
@@ -24002,11 +24416,6 @@ packages:
engines: {node: '>= 8'}
dev: true
- /web-streams-polyfill@4.0.0-beta.3:
- resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
- engines: {node: '>= 14'}
- dev: false
-
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
diff --git a/scripts/builder-entrypoint.sh b/scripts/builder-entrypoint.sh
index 2e6e9e8e450..4e1b4a7ef4f 100644
--- a/scripts/builder-entrypoint.sh
+++ b/scripts/builder-entrypoint.sh
@@ -1,35 +1,15 @@
#!/bin/bash
-ENVSH_ENV=./apps/builder/.env.production ENVSH_OUTPUT=./apps/builder/public/__env.js bash inject-runtime-env.sh
+echo $DATABASE_URL;
-echo 'Checking if required environment variables are set and valid...'
-
-if [ -z "$DATABASE_URL" ]; then
- echo "DATABASE_URL is not set. Exiting..."
- exit 1
-fi
-
-if [ ${#ENCRYPTION_SECRET} -ne 32 ] && [ ${#ENCRYPTION_SECRET} -ne 80 ]; then
- echo "ENCRYPTION_SECRET is not 32 characters long. Exiting... (To generate a valid secret: https://docs.typebot.io/self-hosting/docker#2-add-the-required-configuration)"
- exit 1
-fi
-
-if [ -z "$NEXTAUTH_URL" ]; then
- echo "NEXTAUTH_URL is not set. Exiting..."
- exit 1
-fi
-
-if [ -z "$NEXT_PUBLIC_VIEWER_URL" ]; then
- echo "NEXT_PUBLIC_VIEWER_URL is not set. Exiting..."
- exit 1
-fi
-
-./node_modules/.bin/prisma generate --schema=packages/prisma/postgresql/schema.prisma;
+cd apps/builder;
+node -e "const { configureRuntimeEnv } = require('next-runtime-env/build/configure'); configureRuntimeEnv();"
+cd ../..;
echo 'Waiting 5s for db to be ready...';
sleep 5;
-./node_modules/.bin/prisma migrate deploy --schema=packages/prisma/postgresql/schema.prisma;
+pnpm prisma migrate deploy --schema=packages/prisma/postgresql/schema.prisma;
node apps/builder/server.js;
\ No newline at end of file
diff --git a/scripts/inject-runtime-env.sh b/scripts/inject-runtime-env.sh
deleted file mode 100644
index b416b8d2525..00000000000
--- a/scripts/inject-runtime-env.sh
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/bin/bash
-# env.sh - Dead-simple .env file reader and generator
-# Tunghsiao Liu (t@sparanoid.com)
-#
-# Inspired by:
-# - https://github.com/andrewmclagan/react-env
-# - https://www.freecodecamp.org/news/7f9d42a91d70/
-# - https://github.com/kunokdev/cra-runtime-environment-variables
-#
-# Features:
-# - Designed to be used for Next.js app inside a Docker container (General
-# React app should also work)
-# - Read env file and generate __env.js file for runtime client use
-# - Merge current environment variables passing to it (Useful for Docker images)
-# - No dependencies (More like a lite version of react-env). This is important
-# to keep our container image as small as possible.
-#
-# Usage:
-# - General usage:
-# $ ./env.sh
-#
-# - Replacing varaible:
-# $ NEXT_PUBLIC_API_BASE=xxx ./env.sh
-#
-# - Environment variable not in whitelist will be discarded:
-# $ BAD_ENV=zzz ./env.sh
-#
-# - Change script options:
-# $ ENVSH_ENV="./.env.staging" ENVSH_OUTPUT="./public/config.js" ./env.sh
-#
-# - Use it inside Dockerfile:
-# RUN chmod +x ./env.sh
-# ENTRYPOINT ["./env.sh"]
-#
-# Debug:
-# NEXT_PUBLIC_OB_ENV=123_from_fish NEXT_BAD_ENV=zzz NEXT_PUBLIC_OB_TESTNEW=testenv NEXT_PUBLIC_CODE_UPLOAD_SIZE_LIMIT=6666 ./env.sh
-
-echo -e "env.sh loaded"
-
-# Config
-ENVSH_ENV="${ENVSH_ENV:-"./.env.production"}"
-ENVSH_PREFIX="${ENVSH_PREFIX:-"NEXT_PUBLIC_"}"
-ENVSH_PREFIX_STRIP="${ENVSH_PREFIX_STRIP:-true}"
-
-# Can be `window.__env = {` or `const ENV = {` or whatever you want
-ENVSH_PREPEND="${ENVSH_PREPEND:-"window.__env = {"}"
-ENVSH_APPEND="${ENVSH_APPEND:-"}"}"
-ENVSH_OUTPUT="${ENVSH_OUTPUT:-"./public/__env.js"}"
-
-# Utils
-__green() {
- printf '\033[1;31;32m%b\033[0m' "$1"
-}
-
-__yellow() {
- printf '\033[1;31;33m%b\033[0m' "$1"
-}
-
-__red() {
- printf '\033[1;31;40m%b\033[0m' "$1"
-}
-
-__info() {
- printf "%s\n" "$1"
-}
-
-__debug() {
- ENVSH_VERBOSE="${ENVSH_VERBOSE:-"false"}"
- if [ "$ENVSH_VERBOSE" == "true" ]; then
- printf "ENVSH_VERBOSE: %s\n" "$1"
- fi
-}
-
-ENVSH_SED="sed"
-if [[ "$OSTYPE" == "darwin"* ]]; then
- echo "macOS detected, switching to gsed"
-
- if command -v gsed >/dev/null 2>&1 ; then
- __info "$(__green "Found"): $(gsed --version | head -n 1)"
- else
- __info "gsed not found, trying to install..."
-
- if command -v brew >/dev/null 2>&1 ; then
- __info "$(__green "Found"): $(brew --version | head -n 1)"
- brew install gnu-sed
- else
- __info "$(__red "Homebrew not found, install it first: https://brew.sh/")"
- exit 1;
- fi
-
- fi
-
- ENVSH_SED="gsed"
-fi
-
-# Empty config file
-> "$ENVSH_OUTPUT"
-
-# Create an array from inline variables
-matched_envs=$(env | grep ${ENVSH_PREFIX})
-IFS=$'\n' read -r -d '' -a matched_envs_arr <<< "$matched_envs"
-__info "Matched inline env:"
-for matched_env in "${matched_envs_arr[@]}"; do
- echo $matched_env
-done
-
-# Add assignment
-echo "$ENVSH_PREPEND" >> "$ENVSH_OUTPUT"
-
-# Check if file exists
-[[ -f "$ENVSH_ENV" ]] || { echo "$ENVSH_ENV does not exist" ; exec "$@" ;}
-
-# Process .env for runtime client use
-__info "$(__green "Reading ${ENVSH_ENV}...")"
-while IFS= read -r line
-do
- # Check if this line is a valid environment variable and matches our prefix
- if printf '%s' "$line" | grep -e "=" | grep -e "$ENVSH_PREFIX"; then
-
- # Read and apply environment variable if exists
- # NOTE: <<< here operator not working with `sh`
- awk -F '=' '{print $1 ": \"" (ENVIRON[$1] ? ENVIRON[$1] : $2) "\","}' \
- <<< "$line" >> "$ENVSH_OUTPUT"
- fi
-done < "$ENVSH_ENV"
-echo "$ENVSH_APPEND" >> "$ENVSH_OUTPUT"
-
-# Strip prefix if needed
-$ENVSH_PREFIX_STRIP && $ENVSH_SED -i'' -e "s~$ENVSH_PREFIX~~g" "$ENVSH_OUTPUT"
-
-# NOTE: This step is not necessary because variables on pages inside the
-# Next.js prod server won't be changed. They're already inlined during the
-# build time.
-for matched_env in "${matched_envs_arr[@]}"; do
- echo $matched_env
-done
-
-for i in "${!matched_envs_arr[@]}"; do
- IFS='=' read -ra key_arr <<< "${matched_envs_arr[$i]}"
- key=${key_arr[0]}
-
- if [[ "${matched_envs_arr[$i]}" = *"${key}"* ]]; then
- index="$i"
- __info "Got index from inline env: ${index}, replacing ${key}"
- find "$ENVSH_ENV" -type f -exec $ENVSH_SED -i'' \
- -e "s~$key=.*~${matched_envs_arr[$index]}~g" {} \;
- fi
-done
-
-# Print result
-__debug "$(__green "Done! Final result in ${ENVSH_OUTPUT}:")"
-__debug "`cat "$ENVSH_OUTPUT"`"
-
-__debug "$(__green "Done! Modified ${ENVSH_ENV}:")"
-__debug "`cat "$ENVSH_ENV"`"
-
-__info "$(__green "env.sh done\n")"
-
-# Accepting commands (for Docker)
-exec "$@"
diff --git a/scripts/viewer-entrypoint.sh b/scripts/viewer-entrypoint.sh
index 1b29946f66d..06ea8c51efd 100644
--- a/scripts/viewer-entrypoint.sh
+++ b/scripts/viewer-entrypoint.sh
@@ -1,7 +1,7 @@
#!/bin/bash
-ENVSH_ENV=./apps/viewer/.env.production ENVSH_OUTPUT=./apps/viewer/public/__env.js bash inject-runtime-env.sh
-
-./node_modules/.bin/prisma generate --schema=packages/prisma/postgresql/schema.prisma;
+cd apps/viewer;
+node -e "const { configureRuntimeEnv } = require('next-runtime-env/build/configure'); configureRuntimeEnv();"
+cd ../..;
node apps/viewer/server.js;
\ No newline at end of file
diff --git a/turbo.json b/turbo.json
index c8d9e73e005..dea59225c94 100644
--- a/turbo.json
+++ b/turbo.json
@@ -1,5 +1,6 @@
{
"baseBranch": "origin/main",
+ "globalDotEnv": [".env"],
"pipeline": {
"lint": {
"outputs": []
@@ -15,21 +16,14 @@
"build": {
"dependsOn": ["^build", "@typebot.io/prisma#db:generate"],
"outputs": [".next/**", "dist/**", "build/**"],
- "outputMode": "new-only"
- },
- "build:docker": {
- "dependsOn": ["^build", "@typebot.io/prisma#db:generate"],
- "outputs": [".next/**", "dist/**", "build/**"],
- "outputMode": "new-only"
+ "outputMode": "new-only",
+ "dotEnv": [".env"]
},
"docs#build": {
"dependsOn": ["api:generate"],
"outputs": ["build/**"],
"outputMode": "new-only"
},
- "build:env": {
- "cache": false
- },
"api:generate": {
"dependsOn": ["bot-engine#build", "@typebot.io/prisma#db:generate"],
"cache": false