diff --git a/apps/api/.env.development b/apps/api/.env.development index d4964892..a55fec37 100644 --- a/apps/api/.env.development +++ b/apps/api/.env.development @@ -1,5 +1,5 @@ -BASE_URL=https://api.init.localhost -ALLOWED_API_ORIGINS=https://app.init.localhost +BASE_URL=http://localhost:3000 +ALLOWED_API_ORIGINS=http://localhost:3001 FILES_API_SECRET=dev-files-api-secret-change-me-1234567890 S3_ACCESS_KEY_ID=minioadmin S3_BUCKET=assets @@ -7,14 +7,14 @@ S3_ENDPOINT=http://localhost:8002 S3_REGION=us-east-1 S3_SECRET_ACCESS_KEY=minioadmin AUTH_SECRET=dev-secret -AUTH_TRUSTED_ORIGINS=https://app.init.localhost,https://api.init.localhost +AUTH_TRUSTED_ORIGINS=http://localhost:3001,http://localhost:3000 GITHUB_CLIENT_ID=dev-github-client-id GITHUB_CLIENT_SECRET=dev-github-client-secret GOOGLE_CLIENT_ID=dev-google-client-id GOOGLE_CLIENT_SECRET=dev-google-client-secret DATABASE_URL=postgresql://postgres:postgres@localhost:8001/main REDIS_URL=redis://localhost:8000 -INNGEST_BASE_URL=https://workflows.init.localhost +INNGEST_BASE_URL=http://localhost:4002 INNGEST_DEV=true INNGEST_EVENT_KEY=dev-inngest-event-key INNGEST_SIGNING_KEY=dev-inngest-signing-key diff --git a/apps/api/.env.schema b/apps/api/.env.schema index 96abbd77..79d45d66 100644 --- a/apps/api/.env.schema +++ b/apps/api/.env.schema @@ -45,9 +45,5 @@ S3_REGION= # Object-storage secret credential. S3_SECRET_ACCESS_KEY= -# Optional Portless URL supplied to local commands. -# @optional @public @type=url -PORTLESS_URL= - # Arcjet security credential. ARCJET_KEY= diff --git a/apps/api/package.json b/apps/api/package.json index 7f2f966f..02c0bd61 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -15,8 +15,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "varlock run -- bun --no-env-file --hot src/index.ts", + "dev": "varlock run -- bun --no-env-file --hot src/index.ts", "env:check": "varlock load", "start": "varlock run -- bun --no-env-file --bun src/index.ts" }, @@ -46,9 +45,5 @@ "@tooling/tsconfig": "workspace:*", "@types/bun": "1.3.14", "typescript": "7.0.2" - }, - "portless": { - "name": "api.init", - "script": "dev:app" } } diff --git a/apps/api/src/shared/auth.ts b/apps/api/src/shared/auth.ts index 4670353e..fa2e9ff3 100644 --- a/apps/api/src/shared/auth.ts +++ b/apps/api/src/shared/auth.ts @@ -1,6 +1,7 @@ import { AUTH_ADVANCED_OPTIONS, AUTH_APP_NAME, + AUTH_COOKIE_PREFIX, AUTH_EMAIL_AND_PASSWORD_OPTIONS, AUTH_SESSION_OPTIONS, } from "@init/auth/constants" @@ -13,7 +14,10 @@ import { ENV } from "#shared/env.generated.ts" import { allowedOrigins, baseUrl } from "#shared/utils.ts" export const auth = createAuth({ - advanced: AUTH_ADVANCED_OPTIONS, + // The app's auth instance shares the localhost cookie jar during + // development, so this instance namespaces its cookies to keep the two + // sessions from clobbering each other. + advanced: { ...AUTH_ADVANCED_OPTIONS, cookiePrefix: `${AUTH_COOKIE_PREFIX}-api` }, appName: AUTH_APP_NAME, basePath: "/auth", baseURL: baseUrl, diff --git a/apps/api/src/shared/env.generated.ts b/apps/api/src/shared/env.generated.ts index f5348d7f..f433966d 100644 --- a/apps/api/src/shared/env.generated.ts +++ b/apps/api/src/shared/env.generated.ts @@ -76,13 +76,6 @@ export type CoercedEnvSchema = { */ S3_SECRET_ACCESS_KEY: string; - /** - * **PORTLESS_URL** - * Optional Portless URL supplied to local commands. - * ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M24%2021V9h-2v14h8v-2zm-4-6v-4c0-1.103-.897-2-2-2h-6v14h2v-6h1.48l2.335%206h2.145l-2.333-6H18c1.103%200%202-.897%202-2m-6-4h4v4h-4zM8%2023H4c-1.103%200-2-.897-2-2V9h2v12h4V9h2v12c0%201.103-.897%202-2%202%22%2F%3E%3C%2Fsvg%3E) - */ - PORTLESS_URL?: string; - /** * **ARCJET_KEY** 🔐 _sensitive_ * Arcjet security credential. @@ -253,7 +246,7 @@ export type CoercedEnvSchema = { }; -type _CoercedEnvSchema_3b9f7a4f = CoercedEnvSchema; +type _CoercedEnvSchema_c1330bc4 = CoercedEnvSchema; export type EnvSchemaAsStrings = { [Property in keyof CoercedEnvSchema]: @@ -261,9 +254,9 @@ export type EnvSchemaAsStrings = { : (CoercedEnvSchema[Property] extends boolean ? ('true' | 'false') : string) }; -type _EnvSchemaAsStrings_3b9f7a4f = EnvSchemaAsStrings; +type _EnvSchemaAsStrings_c1330bc4 = EnvSchemaAsStrings; -export type PublicCoercedEnvSchema = Readonly>; +export type PublicCoercedEnvSchema = Readonly>; // re-export of the runtime ENV proxy, typed to this package's schema export const ENV = _ENV as unknown as Readonly; diff --git a/apps/api/src/shared/utils.ts b/apps/api/src/shared/utils.ts index 4172eb4a..02e83769 100644 --- a/apps/api/src/shared/utils.ts +++ b/apps/api/src/shared/utils.ts @@ -3,17 +3,9 @@ import { createFactory } from "hono/factory" import type { AppContext } from "#shared/types.ts" import { ENV } from "#shared/env.generated.ts" -export const baseUrl = ENV.PORTLESS_URL ?? ENV.BASE_URL +export const baseUrl = ENV.BASE_URL -export const allowedOrigins = ENV.PORTLESS_URL - ? ENV.ALLOWED_API_ORIGINS.map( - (origin) => - new URL( - ENV.PORTLESS_URL?.replace(new URL(ENV.BASE_URL).hostname, new URL(origin).hostname) ?? - origin - ).origin - ) - : ENV.ALLOWED_API_ORIGINS +export const allowedOrigins = ENV.ALLOWED_API_ORIGINS /** * A utility function to create Hono apps and middlewares with the correct context type. diff --git a/apps/app/.env.development b/apps/app/.env.development index 86d6b0c3..a7609b6d 100644 --- a/apps/app/.env.development +++ b/apps/app/.env.development @@ -1,6 +1,6 @@ -PUBLIC_BASE_URL=https://app.init.localhost +PUBLIC_BASE_URL=http://localhost:3001 AUTH_SECRET=dev-secret -AUTH_TRUSTED_ORIGINS=https://app.init.localhost +AUTH_TRUSTED_ORIGINS=http://localhost:3001 GITHUB_CLIENT_ID=dev-github-client-id GITHUB_CLIENT_SECRET=dev-github-client-secret GOOGLE_CLIENT_ID=dev-google-client-id diff --git a/apps/app/.env.schema b/apps/app/.env.schema index d282578f..897ec833 100644 --- a/apps/app/.env.schema +++ b/apps/app/.env.schema @@ -16,10 +16,6 @@ PUBLIC_BASE_URL= # @optional @type=url(matches=/^https?:\/\//) PUBLIC_API_URL= -# Optional Portless URL supplied to local server commands. -# @optional @dynamic @type=url -PORTLESS_URL= - # Local Vite server port. # @dynamic @type=port PORT=3001 diff --git a/apps/app/package.json b/apps/app/package.json index 4633fbcb..449aecd9 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -13,8 +13,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "bun --bun vite dev", + "dev": "bun --bun vite dev", "env:check": "varlock load", "env:scan": "test -d .output/public && varlock scan --path .env.schema --path .env.development .output/public", "env:scan:build": "bun --bun vite build", @@ -62,9 +61,5 @@ "tailwindcss": "4.3.3", "typescript": "7.0.2", "vite": "8.1.5" - }, - "portless": { - "name": "app.init", - "script": "dev:app" } } diff --git a/apps/app/src/features/auth/server/index.ts b/apps/app/src/features/auth/server/index.ts index 83f37aad..d270801e 100644 --- a/apps/app/src/features/auth/server/index.ts +++ b/apps/app/src/features/auth/server/index.ts @@ -12,15 +12,13 @@ import { sendEmail } from "@init/email/client" import PasswordReset from "@init/email/templates/password-reset" import { ENV } from "#shared/env.generated.ts" -const trustedOrigins = ENV.PORTLESS_URL - ? [...new Set([...ENV.AUTH_TRUSTED_ORIGINS, ENV.PORTLESS_URL])] - : ENV.AUTH_TRUSTED_ORIGINS +const trustedOrigins = ENV.AUTH_TRUSTED_ORIGINS export const auth = createAuth({ advanced: AUTH_ADVANCED_OPTIONS, appName: AUTH_APP_NAME, basePath: "/api/auth", - baseURL: ENV.PORTLESS_URL ?? ENV.PUBLIC_BASE_URL, + baseURL: ENV.PUBLIC_BASE_URL, database: databaseAdapter(database()), emailAndPassword: { ...AUTH_EMAIL_AND_PASSWORD_OPTIONS, diff --git a/apps/app/src/shared/env.generated.ts b/apps/app/src/shared/env.generated.ts index 3bb7f3a3..c453a1e5 100644 --- a/apps/app/src/shared/env.generated.ts +++ b/apps/app/src/shared/env.generated.ts @@ -27,13 +27,6 @@ export type CoercedEnvSchema = { */ PUBLIC_API_URL?: string; - /** - * **PORTLESS_URL** - * Optional Portless URL supplied to local server commands. - * ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M24%2021V9h-2v14h8v-2zm-4-6v-4c0-1.103-.897-2-2-2h-6v14h2v-6h1.48l2.335%206h2.145l-2.333-6H18c1.103%200%202-.897%202-2m-6-4h4v4h-4zM8%2023H4c-1.103%200-2-.897-2-2V9h2v12h4V9h2v12c0%201.103-.897%202-2%202%22%2F%3E%3C%2Fsvg%3E) - */ - PORTLESS_URL?: string; - /** * **PORT** * Local Vite server port. @@ -134,7 +127,7 @@ export type CoercedEnvSchema = { }; -type _CoercedEnvSchema_8842e194 = CoercedEnvSchema; +type _CoercedEnvSchema_e8481ffe = CoercedEnvSchema; export type EnvSchemaAsStrings = { [Property in keyof CoercedEnvSchema]: @@ -142,9 +135,9 @@ export type EnvSchemaAsStrings = { : (CoercedEnvSchema[Property] extends boolean ? ('true' | 'false') : string) }; -type _EnvSchemaAsStrings_8842e194 = EnvSchemaAsStrings; +type _EnvSchemaAsStrings_e8481ffe = EnvSchemaAsStrings; -export type PublicCoercedEnvSchema = Readonly>; +export type PublicCoercedEnvSchema = Readonly>; // re-export of the runtime ENV proxy, typed to this package's schema export const ENV = _ENV as unknown as Readonly; diff --git a/apps/app/src/shared/utils.ts b/apps/app/src/shared/utils.ts index 024fd4d8..f22806a2 100644 --- a/apps/app/src/shared/utils.ts +++ b/apps/app/src/shared/utils.ts @@ -2,7 +2,7 @@ import { hasWindow } from "@init/utils/env" import { createUrlBuilder } from "@init/utils/url" import { ENV } from "#shared/env.generated.ts" -const baseUrl = hasWindow ? globalThis.location.origin : (ENV.PORTLESS_URL ?? ENV.PUBLIC_BASE_URL) +const baseUrl = hasWindow ? globalThis.location.origin : ENV.PUBLIC_BASE_URL export const buildUrl = createUrlBuilder(baseUrl, getProtocol(baseUrl)) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 53a1124e..99706f6f 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -15,8 +15,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "electron-forge start", + "dev": "electron-forge start", "env:check": "varlock load", "env:scan": "test -d dist && varlock scan --path .env.schema dist", "env:scan:build": "bun --bun vite build --config vite.renderer.config.ts", @@ -63,9 +62,5 @@ "electron": "43.4.0", "typescript": "7.0.2", "vite": "8.1.5" - }, - "portless": { - "name": "desktop.init", - "script": "dev:app" } } diff --git a/apps/docs/.env.development b/apps/docs/.env.development index b1aa55f5..e976078f 100644 --- a/apps/docs/.env.development +++ b/apps/docs/.env.development @@ -1,2 +1,2 @@ -PUBLIC_MARKETING_URL=https://web.init.localhost -PUBLIC_SITE_URL=https://docs.init.localhost +PUBLIC_MARKETING_URL=http://localhost:3006 +PUBLIC_SITE_URL=http://localhost:3004 diff --git a/apps/docs/README.md b/apps/docs/README.md index 42933b3f..fc88d4c2 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -44,8 +44,8 @@ decisions do not enter public routes or search. - Colors and component styling: `src/shared/styles/globals.css` - Site URL: `PUBLIC_SITE_URL` in `.env.schema`, with safe development values in `.env.development` and the production fallback in `src/shared/constants.ts` -- Marketing return URL: `PUBLIC_MARKETING_URL`; development otherwise derives the - matching `web..localhost` URL and production uses `init.now` +- Marketing return URL: `PUBLIC_MARKETING_URL`; development otherwise falls back to + the Web workspace at `http://localhost:3006` and production uses `init.now` - Navigation, locales, edit links, and head metadata: `astro.config.ts` - Favicon and social preview: `public/` diff --git a/apps/docs/package.json b/apps/docs/package.json index 3ef982dc..b849a6db 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -14,8 +14,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "astro dev", + "dev": "astro dev", "env:check": "varlock load", "env:scan": "test -d dist && varlock scan --path .env.schema --path .env.development dist", "env:scan:build": "astro build", @@ -42,9 +41,5 @@ "@varlock/astro-integration": "1.3.0", "tailwindcss": "4.3.3", "typescript": "7.0.2" - }, - "portless": { - "name": "docs.init", - "script": "dev:app" } } diff --git a/apps/docs/src/shared/constants.ts b/apps/docs/src/shared/constants.ts index be818202..f9d69ad9 100644 --- a/apps/docs/src/shared/constants.ts +++ b/apps/docs/src/shared/constants.ts @@ -1,7 +1,7 @@ export const DOCS_DESCRIPTION = "Select the workspaces you need, configure the template, and build with init." export const DOCS_URL = "https://docs.init.now" -export const DEVELOPMENT_MARKETING_URL = "https://web.init.localhost" +export const DEVELOPMENT_MARKETING_URL = "http://localhost:3006" export const GITHUB_URL = "https://github.com/metaideas/init" export const MARKETING_URL = "https://init.now" export const SITE_NAME = "init Docs" diff --git a/apps/extension/package.json b/apps/extension/package.json index 4769a55a..4d8a7c67 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -14,8 +14,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "wxt", + "dev": "wxt", "dev:firefox": "wxt -b firefox", "env:check": "varlock load", "env:scan": "test -d .output && varlock scan --path .env.schema .output", @@ -48,9 +47,5 @@ "vite": "8.1.5", "web-ext": "10.5.0", "wxt": "0.21.1" - }, - "portless": { - "name": "extension.init", - "script": "dev:app" } } diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 1f7afd5b..05a13951 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -13,9 +13,8 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "bun run scripts/codegen.ts", - "dev": "portless", + "dev": "varlock run -- expo start --port ${PORT:-3002}", "dev:android": "varlock run -- expo start --android", - "dev:app": "varlock run -- expo start --port ${PORT:-3002}", "dev:ios": "varlock run -- expo start --ios", "doctor": "expo-doctor", "env:check": "varlock load", @@ -86,9 +85,5 @@ "typescript" ] } - }, - "portless": { - "name": "mobile.init", - "script": "dev:app" } } diff --git a/apps/web/.env.development b/apps/web/.env.development index eb48ae15..2131e168 100644 --- a/apps/web/.env.development +++ b/apps/web/.env.development @@ -1 +1 @@ -PUBLIC_SITE_URL=https://web.init.localhost +PUBLIC_SITE_URL=http://localhost:3006 diff --git a/apps/web/package.json b/apps/web/package.json index 936fbac4..1bc87241 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -14,8 +14,7 @@ "codegen": "bun run --parallel \"codegen:*\"", "codegen:env": "varlock codegen", "codegen:i18n": "paraglide-js compile --project ../../tooling/internationalization/project.inlang --outdir ./src/shared/internationalization", - "dev": "portless", - "dev:app": "astro dev", + "dev": "astro dev", "env:check": "varlock load", "env:scan": "test -d dist && varlock scan --path .env.schema --path .env.development dist", "env:scan:build": "astro build", @@ -45,9 +44,5 @@ "@varlock/astro-integration": "1.3.0", "tailwindcss": "4.3.3", "typescript": "7.0.2" - }, - "portless": { - "name": "web.init", - "script": "dev:app" } } diff --git a/bun.lock b/bun.lock index fe27ee91..297f4c2c 100644 --- a/bun.lock +++ b/bun.lock @@ -14,7 +14,6 @@ "oxfmt": "0.63.0", "oxlint": "1.78.0", "oxlint-tsgolint": "7.0.2001", - "portless": "0.15.5", "sherif": "1.13.0", "turbo": "2.10.7", "typescript": "7.0.2", @@ -4334,8 +4333,6 @@ "pngjs": ["pngjs@3.4.0", "", {}, "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="], - "portless": ["portless@0.15.5", "", { "os": [ "linux", "win32", "darwin", ], "bin": { "portless": "dist/cli.js" } }, "sha512-zmJu4Q8/fY54oVUT/5NnmF4Ih8wTdCvCf6JCN783dRYl9mXkJBzXSckX2lztGCLIbM70varDjCudAbGKT73XPg=="], - "postcss": ["postcss@8.5.25", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw=="], "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], diff --git a/docs/development.md b/docs/development.md index 90b10589..efcaa5c5 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,6 +1,6 @@ --- title: Development -description: Run, build, test, and maintain an init project with Bun, Turbo, Adamantite, and Portless. +description: Run, build, test, and maintain an init project with Bun, Turbo, and Adamantite. sidebar: order: 3 --- @@ -18,9 +18,9 @@ These commands match the scripts in the root `package.json`. | Command | Description | | ---------------------- | ----------------------------------------------------- | -| `bun run dev` | Start all workspaces with named HTTPS URLs. | -| `bun run dev:apps` | Start application workspaces with Portless. | -| `bun run dev:packages` | Start package workspaces with Portless. | +| `bun run dev` | Start all workspaces on their fixed local ports. | +| `bun run dev:apps` | Start application workspaces. | +| `bun run dev:packages` | Start package workspaces. | | `bun run build` | Build all workspaces. | | `bun run clean` | Remove build artifacts. | | `bun run check` | Generate types and run Adamantite checks. | @@ -42,17 +42,24 @@ bun run --filter Application workspaces separate generation into `codegen:env` and `codegen:i18n`. Their `codegen` script runs both commands at the same time with Bun's parallel script runner. Turbo keeps one dependency boundary. You can run either generator independently during development. -## Portless +## Development Servers -Every HTTP-serving workspace uses `portless` as its `dev` script. Each workspace keeps its framework command in `dev:app`, as [Portless recommends for Turborepo](https://portless.sh/configuration). Root commands such as `bun run dev` and local commands such as `cd apps/api && bun run dev` use named HTTPS URLs. The normalized npm scope sets the hostname suffix. For a scope named `example`, the application workspace uses `https://example.localhost`. The API uses `https://api.example.localhost`. Other HTTP development servers use `.example.localhost`. +Each HTTP-serving workspace runs its framework command directly as its `dev` script on a fixed local port. Application workspaces declare the port as the `PORT` default in their `.env.schema`, and their framework configuration reads `ENV.PORT`. The Mobile server and the package development servers set theirs with a `${PORT:-}` fallback in the `dev` script: -The package-local `portless` object in each HTTP-serving workspace defines its project-qualified name and `dev:app` script. Portless assigns an available upstream port at runtime. Multiple projects can run at the same time without shared application ports. Separate projects must use distinct npm scopes and Portless names. Git worktrees receive automatic route prefixes. +| Workspace | URL | +| ----------------- | ----------------------- | +| API | `http://localhost:3000` | +| App | `http://localhost:3001` | +| Mobile server | `http://localhost:3002` | +| Desktop frontend | `http://localhost:3003` | +| Docs | `http://localhost:3004` | +| Extension server | `http://localhost:3005` | +| Web | `http://localhost:3006` | +| Drizzle Studio | `https://local.drizzle.studio?port=4000` | +| Email preview | `http://localhost:4001` | +| Inngest | `http://localhost:4002` | -Drizzle Studio, React Email, and the Inngest development server use the same package-local pattern. Inngest runs from `packages/workflows`. Docker Compose is reserved for data infrastructure. - -The first run can request administrator access to trust the local Portless certificate authority and bind port 443. Use `portless doctor` to examine the proxy, certificate, DNS, and route health. - -Portless routes the Mobile, Desktop, and Extension development servers. It does not replace Expo, Electron, or browser-extension launch behavior. `.localhost` resolves only on the development machine. Physical devices require Portless LAN mode and `.local`. +Package development servers use the 4000 block in alphabetical order: `db` on `4000`, `email` on `4001`, and `workflows` on `4002`. The Inngest development server polls the API workflows endpoint at `http://localhost:3000/workflows`. Drizzle Studio's local server listens on `http://localhost:4000`; open the interface at `https://local.drizzle.studio?port=4000`, since the bare hosted URL connects to Drizzle's default port instead. ## Managing Dependencies diff --git a/docs/generators.md b/docs/generators.md index 1a4fa157..cb3ff1ff 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -99,8 +99,8 @@ Generate the optional client in an application workspace that consumes the API: ```bash bun run generate files-client -bun run generate files-client --args app https://api.init.localhost/files -bun run generate files-client --args web https://api.init.localhost/files +bun run generate files-client --args app http://localhost:3000/files +bun run generate files-client --args web http://localhost:3000/files ``` The template command can target any workspace under `apps/`. It creates `src/shared/files.ts`. It exports the application-local `useFiles` hook, `useFile`, `useList`, and `useSearch`. It authenticates JSON and XHR upload traffic. Astro consumers use the same React integration through the Astro React renderer. diff --git a/docs/getting-started.md b/docs/getting-started.md index 8e233f84..212bbd05 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -79,40 +79,33 @@ Application contracts are in `.env.schema`. Safe local values are committed in ` bun run docker:up ``` -5. Start the development servers with Portless: +5. Start the development servers: ```bash bun run dev ``` -Portless serves local HTTP development servers through named HTTPS URLs. On its first use, it creates a local certificate authority. It asks the operating system to trust the authority. It starts its proxy on port 443. The project scope sets the hostname suffix. The template uses these names by default: +Each workspace serves on a fixed local port. Application workspaces declare the port as the `PORT` default in their `.env.schema`; the Mobile server and package development servers set theirs in their `dev` scripts: -- App: `https://app.init.localhost` -- API: `https://api.init.localhost` -- Web: `https://web.init.localhost` -- Docs: `https://docs.init.localhost` -- Mobile server: `https://mobile.init.localhost` -- Desktop frontend: `https://desktop.init.localhost` -- Extension server: `https://extension.init.localhost` -- Drizzle Studio: `https://db.init.localhost` -- Email preview: `https://email.init.localhost` -- Inngest: `https://workflows.init.localhost` +- API: `http://localhost:3000` +- App: `http://localhost:3001` +- Mobile server: `http://localhost:3002` +- Desktop frontend: `http://localhost:3003` +- Docs: `http://localhost:3004` +- Extension server: `http://localhost:3005` +- Web: `http://localhost:3006` +- Drizzle Studio: `https://local.drizzle.studio?port=4000` (local server on `4000`) +- Email preview: `http://localhost:4001` +- Inngest: `http://localhost:4002` -`bun template setup` or a root `bun template rename` changes `init` in these hostnames to the normalized project scope. The application workspace uses the `app` subdomain. - -Every HTTP-serving workspace uses `portless` as its `dev` script. Each workspace keeps its framework command in `dev:app`. For example, `bun run dev` in `apps/api` serves `https://api.init.localhost`. At the repository root, the same command runs all workspaces through Turbo. The package-local Portless configuration keeps both entry points on the same names. +At the repository root, `bun run dev` runs all workspaces through Turbo. Inside a workspace, the same command starts that workspace alone. ### First Run Checklist - Run `bun template setup`. - Generate source files and types with `bun run codegen`. - Start services with `bun run docker:up`. -- Start the named HTTPS development topology with `bun run dev`. -- If a local URL or certificate is unavailable, run `portless doctor`. - -### Port Allocation - -Portless assigns an available upstream port to each application workspace and package UI at startup. The public HTTPS names stay stable when two projects run at the same time. Separate projects must use different npm scopes. This prevents public-name conflicts. Git worktrees receive automatic route prefixes. Use `portless list` to examine the current assignments. +- Start the development servers with `bun run dev`. #### Infrastructure Ports @@ -128,6 +121,5 @@ Docker infrastructure uses fixed host ports. These ports can conflict across pro - For a Node version mismatch, install Node.js `>=24` with the version manager. - When Docker services do not run, examine `docker ps`. Then run `bun run docker:up`. - For missing environment variables, run `bun run env:check`. Then examine the owning `.env.schema` and the ignored `.env.local` overrides. -- For Portless trust or DNS problems, run `portless doctor`. Then run its suggested `portless trust` or `portless hosts sync` command. -- `.localhost` is available only on the development machine. Expo on a physical device - requires Portless LAN mode and a `.local` hostname. +- For a port conflict, find the process with `lsof -i :`. Application workspace ports are the `PORT` defaults in their `.env.schema`; the Mobile server and package development servers set theirs in their `dev` scripts. +- Expo on a physical device requires the development machine's LAN IP instead of `localhost`. diff --git a/docs/template-commands.md b/docs/template-commands.md index 2f8c6474..ab472cbf 100644 --- a/docs/template-commands.md +++ b/docs/template-commands.md @@ -14,7 +14,6 @@ Configure a newly created project. This command does the following: - It prompts you to select the application and package workspaces to keep. - It sets the project name, which is also the package scope. - It rewrites `@init/` references with the project name. -- It sets package-local Portless route names from the normalized package scope. - It records the source template, commit, and creation time in `.template.json`. ```bash @@ -23,7 +22,7 @@ bun template setup ### `bun template rename` -Rename the project. Rewrite its package scope references. Update its Portless hostnames. +Rename the project. Rewrite its package scope references. ```bash bun template rename --name [--scope ] @@ -31,7 +30,7 @@ bun template rename --name [--scope ] ### `bun template add app ` -Copy an application workspace from the template with Turbo generators. Apply the package scope of the project. Restore its Portless route configuration. +Copy an application workspace from the template with Turbo generators. Apply the package scope of the project. ```bash bun template add app web @@ -39,7 +38,7 @@ bun template add app web ### `bun template add package ` -Copy a package workspace from the template with Turbo generators. Apply the package scope of the project. When it owns a local UI, restore its Portless route configuration. +Copy a package workspace from the template with Turbo generators. Apply the package scope of the project. ```bash bun template add package auth diff --git a/package.json b/package.json index 823ed0e2..57ddfa21 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "oxfmt": "0.63.0", "oxlint": "1.78.0", "oxlint-tsgolint": "7.0.2001", - "portless": "0.15.5", "sherif": "1.13.0", "turbo": "2.10.7", "typescript": "7.0.2", diff --git a/packages/db/package.json b/packages/db/package.json index 50cae3d1..bdc64e73 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -16,8 +16,7 @@ "bump:deps": "bun update --interactive", "clean": "git clean -xdf .cache .turbo dist node_modules", "codegen": "varlock codegen", - "dev": "portless", - "dev:app": "varlock run -- bun --bun drizzle-kit studio --port ${PORT:-4983}", + "dev": "varlock run -- bun --bun drizzle-kit studio --port ${PORT:-4000}", "env:check": "varlock load", "generate": "varlock run -- bun --bun drizzle-kit generate", "migrate": "varlock run -- bun --bun drizzle-kit migrate", @@ -38,9 +37,5 @@ "drizzle-seed": "0.3.1", "postgres": "3.4.9", "typescript": "7.0.2" - }, - "portless": { - "name": "db.init", - "script": "dev:app" } } diff --git a/packages/email/package.json b/packages/email/package.json index a6f4be11..a53b8db8 100644 --- a/packages/email/package.json +++ b/packages/email/package.json @@ -12,8 +12,7 @@ "bump:deps": "bun update --interactive", "clean": "git clean -xdf .cache .turbo dist node_modules", "codegen": "varlock codegen", - "dev": "portless", - "dev:app": "email dev --dir src/templates --port ${PORT:-4000}", + "dev": "email dev --dir src/templates --port ${PORT:-4001}", "env:check": "varlock load", "export": "email export --dir src/templates" }, @@ -35,9 +34,5 @@ "react": "19.2.3", "react-email": "6.9.1", "typescript": "7.0.2" - }, - "portless": { - "name": "email.init", - "script": "dev:app" } } diff --git a/packages/workflows/package.json b/packages/workflows/package.json index 48a13792..e636384c 100644 --- a/packages/workflows/package.json +++ b/packages/workflows/package.json @@ -15,8 +15,7 @@ "scripts": { "bump:deps": "bun update --interactive", "clean": "git clean -xdf .cache .turbo dist node_modules", - "dev": "portless", - "dev:app": "inngest dev --port ${PORT:-8288} --connect-executor-grpc-port $(( ${PORT:-8288} + 10000 )) --connect-gateway-grpc-port $(( ${PORT:-8288} + 11000 )) --connect-gateway-port $(( ${PORT:-8288} + 12000 ))" + "dev": "inngest dev --no-discovery --port ${PORT:-4002} -u http://localhost:3000/workflows" }, "dependencies": { "@init/observability": "workspace:*", @@ -27,9 +26,5 @@ "@tooling/tsconfig": "workspace:*", "inngest-cli": "1.40.0", "typescript": "7.0.2" - }, - "portless": { - "name": "workflows.init", - "script": "dev:app" } } diff --git a/scripts/template/add.ts b/scripts/template/add.ts index 8584d206..6d8568de 100644 --- a/scripts/template/add.ts +++ b/scripts/template/add.ts @@ -2,7 +2,6 @@ import { join } from "node:path" import consola from "consola" import { defineCommand } from "citty" -import { restorePortlessWorkspaces } from "./portless" import { renameProject } from "./rename" import { getDependencyNames, @@ -159,7 +158,6 @@ export default defineCommand({ } const copiedPaths = await addWorkspaces(rootDir, scope, [target], new Set([targetPath])) - await restorePortlessWorkspaces(rootDir, copiedPaths, scope) consola.success(`Added ${copiedPaths.join(", ")}. Run bun install to link the new workspaces.`) }, }) diff --git a/scripts/template/portless.ts b/scripts/template/portless.ts deleted file mode 100644 index 5726b438..00000000 --- a/scripts/template/portless.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { join, relative } from "node:path" - -import { getWorkspaces, readJson, writeJson } from "./shared" - -export function getWorkspaceRouteName(workspacePath: string, projectName: string) { - const normalizedWorkspacePath = workspacePath.replaceAll("\\", "/") - if (normalizedWorkspacePath === "apps/app") return projectName - - const workspaceName = normalizedWorkspacePath.split("/").at(-1) - return workspaceName ? `${workspaceName}.${projectName}` : projectName -} - -async function updateWorkspacePackageName( - rootDir: string, - workspacePath: string, - projectName: string -) { - const packageJsonPath = join(rootDir, workspacePath, "package.json") - if (!(await Bun.file(packageJsonPath).exists())) return null - - const packageJson = await readJson(packageJsonPath) - const portless = packageJson.portless as { name?: string } | undefined - if (!portless) return null - - const routeName = getWorkspaceRouteName(workspacePath, projectName) - if (portless.name === routeName) return null - - portless.name = routeName - await writeJson(packageJsonPath, packageJson) - - return packageJsonPath -} - -async function updateWorkspaceNames( - rootDir: string, - workspacePaths: string[], - projectName: string -) { - const changedFiles = await Promise.all( - workspacePaths.map((workspacePath) => - updateWorkspacePackageName(rootDir, workspacePath, projectName) - ) - ) - - return changedFiles.filter((path): path is string => path !== null) -} - -export async function updatePortlessProjectName(rootDir: string, projectName: string) { - const workspaces = await Promise.all([ - getWorkspaces(rootDir, "app"), - getWorkspaces(rootDir, "package"), - ]) - const workspacePaths = workspaces - .flat() - .map((workspace) => relative(rootDir, workspace.directory)) - - return updateWorkspaceNames(rootDir, workspacePaths, projectName) -} - -export async function restorePortlessWorkspaces( - rootDir: string, - workspacePaths: string[], - projectName: string -) { - return updateWorkspaceNames(rootDir, workspacePaths, projectName) -} diff --git a/scripts/template/rename.ts b/scripts/template/rename.ts index 27b61daf..eccca622 100644 --- a/scripts/template/rename.ts +++ b/scripts/template/rename.ts @@ -2,7 +2,6 @@ import { join, resolve } from "node:path" import { defineCommand } from "citty" import consola from "consola" -import { updatePortlessProjectName } from "./portless" import { checkIsPathWithinRoot, getProjectScope, @@ -40,18 +39,8 @@ export async function renameProject({ ) ) - for (const path of await replaceTextInFiles( - rootDir, - `${normalizedSourceScope}.localhost`, - `${normalizedScope}.localhost` - )) - changedFiles.add(path) - if (!projectName) return { changedFiles: [...changedFiles] } - for (const path of await updatePortlessProjectName(rootDir, normalizedScope)) - changedFiles.add(path) - const packageJsonPath = join(rootDir, "package.json") const packageJson = await readJson(packageJsonPath) if (packageJson.name !== projectName) { diff --git a/turbo.json b/turbo.json index f8abde83..bc3efd7c 100644 --- a/turbo.json +++ b/turbo.json @@ -19,7 +19,6 @@ "INNGEST_*", "MOCK_RESEND", "PORT", - "PORTLESS_URL", "POSTHOG_*", "PUBLIC_*", "REDIS_URL", @@ -45,10 +44,6 @@ "cache": false, "interactive": true }, - "studio": { - "cache": false, - "persistent": true - }, "start": { "cache": false, "persistent": true diff --git a/turbo/generators/commands/connect-backend.ts b/turbo/generators/commands/connect-backend.ts index 4bd25259..5731beb5 100644 --- a/turbo/generators/commands/connect-backend.ts +++ b/turbo/generators/commands/connect-backend.ts @@ -526,12 +526,12 @@ type EnvironmentEntry = { const API_ENVIRONMENTS = { desktop: { - developmentValue: "https://api.init.localhost", + developmentValue: "http://localhost:3000", key: "PUBLIC_API_URL", schema: "# Remote API URL.\n# @public @type=url(matches=/^https?:\\/\\//)\nPUBLIC_API_URL=", }, mobile: { - developmentValue: "https://api.init.localhost", + developmentValue: "http://localhost:3000", key: "EXPO_PUBLIC_API_URL", schema: "# Remote API URL.\n# @public @static @type=url(matches=/^https?:\\/\\//)\nEXPO_PUBLIC_API_URL=", diff --git a/turbo/generators/commands/files-client.ts b/turbo/generators/commands/files-client.ts index 91260781..8c55f83b 100644 --- a/turbo/generators/commands/files-client.ts +++ b/turbo/generators/commands/files-client.ts @@ -103,7 +103,7 @@ export function registerFilesClientGenerator(plop: PlopTypes.NodePlopAPI): void type: "list", }, { - default: "https://api.init.localhost/files", + default: "http://localhost:3000/files", message: "What is the Files SDK endpoint?", name: "endpoint", type: "input",