Skip to content

Commit 3cb145c

Browse files
letstricursoragent
andauthored
feat: add portless integration for local HTTPS development (#450)
Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Valerii Strilets <letstri@users.noreply.github.com>
1 parent 8d7dc51 commit 3cb145c

22 files changed

Lines changed: 481 additions & 204 deletions

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,21 @@ Conar is an AI-powered open-source project that simplifies database interactions
7373

7474
- **🚀 Run the Project**
7575

76-
This will start all development servers using Turbo.
76+
This starts all development servers through [portless](https://portless.sh) (HTTPS on `.local.conar.app` domains):
77+
78+
| Service | URL |
79+
| --- | --- |
80+
| API | https://api.local.conar.app |
81+
| App | https://app.local.conar.app |
82+
| Main | https://main.local.conar.app |
83+
| Proxy | https://proxy.local.conar.app |
84+
7785
```bash
7886
pnpm run dev
7987
```
8088

89+
To run a single app without Turbo, `cd` into its directory (e.g. `apps/api`) and run `pnpm run dev`.
90+
8191
## Testing
8292

8393
- **Unit Tests**

apps/api/.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
API_URL=http://localhost:3000
2-
MAIN_URL=http://localhost:3002
1+
API_URL=https://api.local.conar.app
2+
MAIN_URL=https://main.local.conar.app
33
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/conar
44
ALERTS_EMAIL=
55
ENCRYPTION_SECRET=example

apps/api/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { anthropic } from '@ai-sdk/anthropic'
55
import { google } from '@ai-sdk/google'
66
import { openai } from '@ai-sdk/openai'
77
import { xai } from '@ai-sdk/xai'
8-
import { PORTS } from '@conar/shared/constants'
98
import { ORPCError, ValidationError } from '@orpc/server'
109
import { RPCHandler } from '@orpc/server/fetch'
1110
import { generateText } from 'ai'
@@ -65,11 +64,9 @@ const app = new Hono<{
6564
.use(cors({
6665
origin(origin) {
6766
const allowedOrigins = [
68-
env.MAIN_URL,
69-
...(nodeEnv === 'development' ? [`http://localhost:${PORTS.DEV.DESKTOP}`, `http://localhost:${PORTS.DEV.APP}`, `http://localhost:${PORTS.DEV.PROXY}`] : []),
70-
...(nodeEnv === 'test' ? [`http://localhost:${PORTS.TEST.DESKTOP}`, `http://localhost:${PORTS.TEST.APP}`, `http://localhost:${PORTS.TEST.PROXY}`] : []),
67+
'https://conar.app',
7168
]
72-
return origin.endsWith(`.${new URL(env.MAIN_URL).host}`) || allowedOrigins.includes(origin) ? origin : null
69+
return origin.endsWith('.conar.app') || allowedOrigins.includes(origin) ? origin : null
7370
},
7471
credentials: true,
7572
}))
@@ -237,7 +234,12 @@ const app = new Hono<{
237234

238235
export default {
239236
fetch: app.fetch,
240-
port: process.env.PORT
241-
? Number(process.env.PORT)
242-
: nodeEnv === 'test' ? PORTS.TEST.API : PORTS.DEV.API,
237+
port: Number(process.env.PORT || 3000),
238+
// Electric live shape requests (`live=true`) long-poll: Electric holds the
239+
// connection open (~20 s) until new data arrives or the poll window elapses.
240+
// Bun's default 30 s idle timeout can close these mid-poll, so portless sees
241+
// a reset and serves its 502 page. Raise the ceiling above the poll window
242+
// (255 s is Bun's max) so legitimate polls survive while truly stuck sockets
243+
// still time out.
244+
idleTimeout: 255,
243245
}

apps/api/lib/auth.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { db } from '@conar/db'
44
import { users } from '@conar/db/schema'
55
import * as schema from '@conar/db/schema'
66
import { infisical } from '@conar/infisical'
7-
import { API_KEY_PERMISSIONS, AUTH_COOKIE_PREFIX, PORTS } from '@conar/shared/constants'
7+
import { API_KEY_PERMISSIONS, AUTH_COOKIE_PREFIX } from '@conar/shared/constants'
88
import { betterAuth } from 'better-auth'
99
import { emailHarmony } from 'better-auth-harmony'
1010
import { createAuthMiddleware } from 'better-auth/api'
@@ -16,8 +16,6 @@ import { env, nodeEnv } from '~/env'
1616
import { resend, sendEmail } from '~/lib/resend'
1717
import { redisMemoize } from './redis'
1818

19-
const mainUrl = new URL(env.MAIN_URL)
20-
2119
export const auth = betterAuth({
2220
appName: 'Conar',
2321
secret: env.BETTER_AUTH_SECRET,
@@ -186,17 +184,15 @@ export const auth = betterAuth({
186184
},
187185
},
188186
trustedOrigins: [
189-
env.MAIN_URL,
190-
`${mainUrl.protocol}//*.${mainUrl.host}`,
187+
'https://conar.app',
188+
'https://*.conar.app',
191189
'file://',
192-
...(nodeEnv === 'development' ? [`http://localhost:${PORTS.DEV.DESKTOP}`, `http://localhost:${PORTS.DEV.APP}`] : []),
193-
...(nodeEnv === 'test' ? [`http://localhost:${PORTS.TEST.DESKTOP}`, `http://localhost:${PORTS.TEST.APP}`] : []),
194190
],
195191
advanced: {
196192
cookiePrefix: AUTH_COOKIE_PREFIX,
197193
crossSubDomainCookies: {
198-
enabled: nodeEnv === 'production',
199-
domain: mainUrl.host,
194+
enabled: true,
195+
domain: 'conar.app',
200196
},
201197
database: {
202198
generateId: 'uuid',

apps/api/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
22
"name": "@conar/api",
33
"type": "module",
4+
"portless": "api.local.conar",
45
"scripts": {
5-
"dev": "cross-env NODE_ENV=development bun --watch run ./index.ts",
6-
"start": "cross-env NODE_ENV=production bun run ./index.ts",
6+
"dev": "portless run cross-env NODE_ENV=development BUN_CONFIG_MAX_HTTP_REQUESTS=4096 bun --watch run ./index.ts",
7+
"start": "cross-env NODE_ENV=production BUN_CONFIG_MAX_HTTP_REQUESTS=4096 bun run ./index.ts",
78
"check-types": "tsgo",
89
"test:start": "cross-env NODE_ENV=test bun --env-file=.env.test drizzle-kit migrate && cross-env NODE_ENV=test bun --env-file=.env.test run ./index.ts",
910
"better-auth:generate": "cross-env NODE_ENV=development pnpx https://pkg.pr.new/auth@9489 generate --output ../../packages/db/schema/auth.ts"

apps/app/.env.example

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
VITE_PUBLIC_API_URL=http://localhost:3000
2-
VITE_PUBLIC_WEB_URL=http://localhost:3001
3-
VITE_PUBLIC_MAIN_URL=http://localhost:3002
4-
VITE_PUBLIC_PROXY_URL=http://localhost:3004
1+
VITE_PUBLIC_API_URL=https://api.local.conar.app
2+
VITE_PUBLIC_WEB_URL=https://app.local.conar.app
3+
VITE_PUBLIC_MAIN_URL=https://main.local.conar.app
4+
VITE_PUBLIC_PROXY_URL=https://proxy.local.conar.app
55
VITE_PUBLIC_POSTHOG_TOKEN=

apps/app/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "@conar/app",
33
"type": "module",
4-
"private": true,
4+
"portless": "app.local.conar",
55
"scripts": {
6-
"dev": "vite dev",
6+
"dev": "portless run vite dev",
77
"build": "vite build",
88
"build:desktop": "vite build --mode desktop",
99
"start": "serve -s dist -l $PORT",

apps/app/playwright.config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { PORTS } from '@conar/shared/constants'
21
import { defineConfig, devices } from '@playwright/test'
32

43
export default defineConfig({
54
testDir: './e2e',
65
fullyParallel: true,
76
reporter: [['html', { open: 'never' }]],
87
use: {
9-
baseURL: `http://localhost:${PORTS.TEST.DESKTOP}`,
8+
baseURL: 'https://app.conar.localhost',
109
trace: 'on-first-retry',
1110
},
1211
projects: [

apps/app/vite.config.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import tailwindcss from '@tailwindcss/vite'
33
import { tanstackRouter } from '@tanstack/router-plugin/vite'
44
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
55
import { defineConfig } from 'vite'
6-
import { PORTS } from '../../packages/shared/constants'
76

87
export default defineConfig(({ mode }) => ({
98
resolve: {
@@ -27,8 +26,4 @@ export default defineConfig(({ mode }) => ({
2726
presets: [reactCompilerPreset()],
2827
}),
2928
],
30-
server: {
31-
strictPort: true,
32-
port: mode === 'test' ? PORTS.TEST.DESKTOP : PORTS.DEV.APP,
33-
},
3429
}))

apps/cli/.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
API_URL=http://localhost:3000
2-
MAIN_URL=http://localhost:3002
1+
API_URL=https://api.local.conar.app
2+
MAIN_URL=https://main.local.conar.app

0 commit comments

Comments
 (0)