Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
id: filter
with:
filters: |
desktop:
- 'apps/desktop/**'
rust:
- '.cargo/**'
- '.github/**'
Expand Down Expand Up @@ -154,6 +156,8 @@ jobs:

build-desktop:
name: Build Desktop
needs: changes
if: needs.changes.outputs.rust == 'true' || needs.changes.outputs.desktop == 'true'
strategy:
fail-fast: false
matrix:
Expand Down
29 changes: 0 additions & 29 deletions apps/web/app/api/waitlist/route.ts

This file was deleted.

4 changes: 4 additions & 0 deletions apps/web/content/docs/self-hosting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ To send login links via email, you'll need to configure [Resend](https://resend.
2. Connect a domain and set it as `RESEND_FROM_DOMAIN`
3. Generate an API key and set it as `RESEND_API_KEY`

## Other Configuration

See [`env/server.ts`](https://github.com/CapSoftware/Cap/blob/main/packages/env/server.ts) for a description of all environment variables you can configure.

## Support

If you encounter a problem with the Docker image or think this documentation is lacking,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/instrumentation.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export async function register() {

async function createS3Bucket() {
const s3Client = new S3Client({
endpoint: serverEnv().CAP_AWS_ENDPOINT,
endpoint: serverEnv().S3_INTERNAL_ENDPOINT,
region: serverEnv().CAP_AWS_REGION,
credentials: {
accessKeyId: serverEnv().CAP_AWS_ACCESS_KEY ?? "",
Expand Down
2 changes: 1 addition & 1 deletion apps/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const nextConfig = {
env: {
appVersion: version,
},
// If the DOCKER_BUILD environment variable is set to true, we are output nextjs to standalone ready for docker deployment
// If the NEXT_PUBLIC_DOCKER_BUILD environment variable is set to true, we are output nextjs to standalone ready for docker deployment
output:
process.env.NEXT_PUBLIC_DOCKER_BUILD === "true" ? "standalone" : undefined,
// webpack: (config) => {
Expand Down
5 changes: 2 additions & 3 deletions packages/database/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { Config } from "drizzle-kit";

const URL = process.env.DATABASE_MIGRATION_URL ?? process.env.DATABASE_URL;
const URL = process.env.DATABASE_URL;

if (!URL)
throw new Error("DATABASE_URL or DATABASE_MIGRATION_URL must be set!");
if (!URL) throw new Error("DATABASE_URL must be set!");
if (!URL?.startsWith("mysql://"))
throw new Error(
"DATABASE_URL must be a 'mysql://' URI. Drizzle Kit doesn't support the fetch adapter!",
Expand Down
103 changes: 76 additions & 27 deletions packages/env/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,86 @@ const boolString = (_default = false) =>
function createServerEnv() {
return createEnv({
server: {
NODE_ENV: z.string(),
DATABASE_URL: z.string(),
WEB_URL: z.string(),
DATABASE_MIGRATION_URL: z.string().optional(),
DATABASE_ENCRYPTION_KEY: z.string().optional(),
S3_PATH_STYLE: boolString(true),
/// General configuration
DATABASE_URL: z.string().describe("MySQL database URL"),
WEB_URL: z
.string()
.describe("Public URL of the server eg. https://cap.so"),
NEXTAUTH_SECRET: z.string().describe("32 byte base64 string"),
NEXTAUTH_URL: z.string().describe("Should be the same as WEB_URL"),
DATABASE_ENCRYPTION_KEY: z
.string()
.optional()
.describe(
"32 byte hex string for encrypting values like AWS access keys",
),

// Cap uses Resend for email sending, including sending login code emails
RESEND_API_KEY: z.string().optional(),
RESEND_FROM_DOMAIN: z.string().optional(),

/// S3 configuration
// Though they are prefixed with `CAP_AWS`, these don't have to be
// for AWS, and can instead be for any S3-compatible service
CAP_AWS_BUCKET: z.string(),
CAP_AWS_REGION: z.string(),
CAP_AWS_BUCKET_URL: z.string().optional(),
CAP_AWS_ACCESS_KEY: z.string().optional(),
CAP_AWS_SECRET_KEY: z.string().optional(),
CAP_AWS_ENDPOINT: z.string().optional(),
CAP_AWS_MEDIACONVERT_ROLE_ARN: z.string().optional(),
S3_PUBLIC_ENDPOINT: z
.string()
.optional()
.describe("Public endpoint for accessing S3"),
S3_INTERNAL_ENDPOINT: z
.string()
.optional()
.describe(
"Internal endpoint for accessing S3. This is useful if accessing S3 over public internet is more expensive than via your hosting environment's local network.",
),
S3_PATH_STYLE: boolString(true).describe(
"Whether the bucket should be accessed using path-style URLs (common for non-AWS providers, eg. '/{bucket}/{key}') or virtual-hosted-style URLs (eg. '{bucket}.s3.amazonaws.com/{key}').",
),

/// CloudFront configuration
// Configure these if you'd like to serve assets from the default bucket via CloudFront
// In this case, CAP_AWS_BUCKET_URL should be your CloudFront distribution's URL
CAP_AWS_BUCKET_URL: z
.string()
.optional()
.describe("Public URL of the S3 bucket"),
CAP_CLOUDFRONT_DISTRIBUTION_ID: z.string().optional(),
NEXTAUTH_SECRET: z.string(),
NEXTAUTH_URL: z.string(),
CLOUDFRONT_KEYPAIR_ID: z.string().optional(),
CLOUDFRONT_KEYPAIR_PRIVATE_KEY: z.string().optional(),

/// Google Auth
// Provide these to allow Google login
GOOGLE_CLIENT_ID: z.string().optional(),
GOOGLE_CLIENT_SECRET: z.string().optional(),

/// WorkOS SSO
// Provide these to use WorkOS for enterprise SSO
WORKOS_CLIENT_ID: z.string().optional(),
WORKOS_API_KEY: z.string().optional(),
DUB_API_KEY: z.string().optional(),
RESEND_API_KEY: z.string().optional(),
RESEND_FROM_DOMAIN: z.string().optional(),
DEEPGRAM_API_KEY: z.string().optional(),
NEXT_LOOPS_KEY: z.string().optional(),

/// Settings
CAP_VIDEOS_DEFAULT_PUBLIC: boolString(true).describe(
"Should videos be public or private by default",
),
CAP_ALLOWED_SIGNUP_DOMAINS: z
.string()
.optional()
.describe("Comma-separated list of permitted signup domains"),

/// AI providers
DEEPGRAM_API_KEY: z.string().optional().describe("Audio transcription"),
OPENAI_API_KEY: z.string().optional().describe("AI summaries"),
GROQ_API_KEY: z.string().optional().describe("AI summaries"),

/// Cap Cloud
// These are only needed for Cap Cloud (https://cap.so)
STRIPE_SECRET_KEY: z.string().optional(),
STRIPE_WEBHOOK_SECRET: z.string().optional(),
DISCORD_FEEDBACK_WEBHOOK_URL: z.string().optional(),
DISCORD_LOGS_WEBHOOK_URL: z.string().optional(),
OPENAI_API_KEY: z.string().optional(),
GROQ_API_KEY: z.string().optional(),
INTERCOM_SECRET: z.string().optional(),
CAP_VIDEOS_DEFAULT_PUBLIC: boolString(true),
CAP_ALLOWED_SIGNUP_DOMAINS: z.string().optional(),
VERCEL_ENV: z
.union([
z.literal("production"),
Expand All @@ -59,18 +105,21 @@ function createServerEnv() {
VERCEL_URL_HOST: z.string().optional(),
VERCEL_BRANCH_URL_HOST: z.string().optional(),
VERCEL_PROJECT_PRODUCTION_URL_HOST: z.string().optional(),
DOCKER_BUILD: z.string().optional(),
POSTHOG_PERSONAL_API_KEY: z.string().optional(),
CLOUDFRONT_KEYPAIR_ID: z.string().optional(),
CLOUDFRONT_KEYPAIR_PRIVATE_KEY: z.string().optional(),
S3_PUBLIC_ENDPOINT: z.string().optional(),
S3_INTERNAL_ENDPOINT: z.string().optional(),
VERCEL_AWS_ROLE_ARN: z.string().optional(),
POSTHOG_PERSONAL_API_KEY: z.string().optional(),
DUB_API_KEY: z.string().optional(),
INTERCOM_SECRET: z.string().optional(),

/// Ignore
NODE_ENV: z.string(),
WORKFLOWS_RPC_URL: z.string().optional(),
WORKFLOWS_RPC_SECRET: z.string().optional(),
},
experimental__runtimeEnv: {
S3_PUBLIC_ENDPOINT: process.env.CAP_AWS_ENDPOINT,
S3_INTERNAL_ENDPOINT: process.env.CAP_AWS_ENDPOINT,
...process.env,
NODE_ENV: process.env.NODE_ENV ?? "production",
VERCEL_URL_HOST: process.env.VERCEL_URL,
VERCEL_BRANCH_URL_HOST: process.env.VERCEL_BRANCH_URL,
VERCEL_PROJECT_PRODUCTION_URL_HOST:
Expand Down
11 changes: 0 additions & 11 deletions scripts/env-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,9 @@ async function main() {
allEnvs.DATABASE_URL ??
"mysql://root:@localhost:3306/planetscale",
}),
DATABASE_MIGRATION_URL: (v) => {
if (v.results.DATABASE_URL?.startsWith("http")) {
log.info("Planetscale HTTP URL detected");
return text({
message: "DATABASE_MIGRATION_URL",
});
}
},
});

envs.DATABASE_URL = dbValues.DATABASE_URL;
if (dbValues.DATABASE_MIGRATION_URL)
envs.DATABASE_MIGRATION_URL = dbValues.DATABASE_MIGRATION_URL;

log.info("S3 Envs");

Expand Down Expand Up @@ -138,7 +128,6 @@ async function main() {
envs = { ...envs, ...s3Values };
} else {
envs.DATABASE_URL = DOCKER_DB_ENVS.url;
envs.DATABASE_MIGRATION_URL = DOCKER_DB_ENVS.url;

envs.CAP_AWS_ACCESS_KEY = DOCKER_S3_ENVS.accessKey;
envs.CAP_AWS_SECRET_KEY = DOCKER_S3_ENVS.secretKey;
Expand Down