Skip to content

fix: unbreak non-JS integration install flow (Django, .NET, Kotlin + others)#125

Merged
nicknisi merged 4 commits intomainfrom
nicknisi/django-issue
Apr 23, 2026
Merged

fix: unbreak non-JS integration install flow (Django, .NET, Kotlin + others)#125
nicknisi merged 4 commits intomainfrom
nicknisi/django-issue

Conversation

@nicknisi
Copy link
Copy Markdown
Member

@nicknisi nicknisi commented Apr 23, 2026

Summary

Fixes: workos install crashed with "Could not find package.json" in Django projects — and audits the rest of the non-JS integrations for similar narrowness. Several were quietly broken:

  • Django projects crashed before any non-JS integration could run.
  • .NET detection was 100% broken (a glob pattern passed to a literal-filename check).
  • Kotlin detection only matched build.gradle.kts, missing Groovy DSL and Maven projects.
  • All non-JS projects got a .env.local polluted with JS-flavored vars alongside their real .env.
  • Port detection fell back to 3000 for every non-JS integration — wrong for every one of them, and no per-project detection existed even when the port was sitting in a canonical config file.

Root cause (Django crash)

JS integration detection calls getPackageDotJson(), which calls process.exit(1) when no package.json exists. Next.js is the highest-priority integration (100), so detection always tried it first and killed the installer before non-JS integrations got a turn.

Changes

Crash fix + Django detection

  • Skip JS detection when package.json is missing.
  • Widen Python detection to match manage.py or requirements.txt with django, not just pyproject.toml. Added via a new optional detect() override on FrameworkMetadata, wired to the existing isDjangoProject helper.

Broader non-JS audit

  • .NET: manifestFile: '*.csproj' went through existsSync() (literal-filename matching) so it never matched. Now uses a proper readdirSync scan for .csproj.
  • Kotlin: widened to build.gradle (Groovy DSL) and pom.xml (Maven).
  • Left alone: Ruby (Gemfile), PHP (composer.json), Go (go.mod), Elixir (mix.exs) — these manifests are universal in their ecosystems.

Env file handling for non-JS

  • New writeCredentialsEnv() picks .env instead of .env.local when no package.json is present, and skips WORKOS_COOKIE_PASSWORD generation (non-JS SDKs don't use it). Used by unclaimed env provisioning.
  • Gated the state-machine configureEnvironment actor on JS-only so it doesn't overwrite non-JS env files with JS defaults.
  • ensureGitignore() now parameterized on filename — writes .env for non-JS, .env.local for JS.

Port defaults

Added ecosystem defaults for every non-JS integration in cli.config.ts and mapped them in port-detection.ts:

Integration Port Notes
python 8000 Django default
ruby 3000 Rails default
php 8000 php -S default
php-laravel 8000 artisan serve default
go 8080 common for Gin/Echo
dotnet 5000 ASP.NET Core dev default
elixir 4000 Phoenix default
kotlin 8080 Spring Boot default

Port detection (not just defaults)

For languages with a canonical config file, parse the actual configured port before falling back to the default. Mirrors the existing parsers for Next.js / Vite / TanStack Start.

Integration Source
dotnet Properties/launchSettings.jsonprofiles[*].applicationUrl
elixir config/dev.exs or config/runtime.exsport: NNNN
kotlin src/main/resources/application.properties or .ymlserver.port
ruby config/puma.rbport ENV.fetch("PORT") { N } or literal

Python (Django), Go, plain PHP, and Laravel stay on defaults — none has a canonical config file; ports are CLI args or hardcoded in source.

Cleanup

Deleted src/lib/language-detection.ts. The detectLanguage() function + LANGUAGE_DETECTORS table were never called from the install path. The only still-used pieces (globExists, detectKotlin) were inlined into the dotnet and kotlin integrations as caller-specific helpers. The Language type moved into framework-config.ts where it's consumed.

Previously `workos install` crashed with "Could not find package.json"
in any project without a package.json: JS integration detection calls
getPackageDotJson() which exits the process on missing file, killing
the installer before non-JS integrations (Python/Django) got a turn.

- Skip JS integration detection when package.json is missing
- Widen Python detection: match manage.py or requirements.txt with
  django, not just pyproject.toml (via a new optional detect() override
  on FrameworkMetadata, wired to the existing isDjangoProject helper)
- Write credentials to .env (not .env.local) and skip cookie password
  generation for non-JS projects in unclaimed env provisioning
- Gate state-machine configureEnvironment actor on JS-only to prevent
  a second .env.local leak post-detection
- Add Django port/callback defaults (8000, /auth/callback/) so
  detectPort returns the right values for Python

Tests: +8 net covering detection matrix (no-package.json skip,
pyproject.toml, manage.py alone, requirements.txt+django, non-Django
python), python port defaults, and .env vs .env.local selection in
unclaimed provisioning.
…languages

Beyond the Django fixes in the previous commit, several other non-JS
integrations had parallel problems that would bite the next user with a
.NET, Kotlin, or non-trivial project layout.

- .NET detection was completely broken: manifestFile '*.csproj' went
  through existsSync() which does literal-filename matching, so it never
  matched. Now uses globExists() from language-detection.ts (which has
  the right logic but wasn't wired up anywhere).
- Kotlin detection only matched build.gradle.kts (Kotlin DSL). Now also
  matches build.gradle (Groovy DSL) and pom.xml (Maven) via the existing
  detectKotlin() helper, which already had Gradle Groovy support.
  Extended it to cover Maven too.
- Port defaults added for ruby (3000), php (8000), php-laravel (8000),
  go (8080), dotnet (5000), elixir (4000), kotlin (8080). Previously all
  fell back to DEFAULT_PORT=3000, which is wrong for every one of them.
- ensureGitignore() now also writes .env to .gitignore for non-JS
  projects (previously only handled .env.local for JS).

Exported globExists() and detectKotlin() from language-detection.ts so
the integrations can share them. detectLanguage() itself still isn't
called anywhere in the install path — that's a larger cleanup for later.
@nicknisi nicknisi changed the title fix: support Django projects end-to-end in workos install fix: unbreak non-JS integration install flow (Django, .NET, Kotlin + others) Apr 23, 2026
…t, Rails

Follow-up to the hardcoded ecosystem defaults. These four languages have a
canonical config file where the dev server port lives; parse it so we don't
misconfigure redirect URIs when the user has customized the port.

- .NET: Properties/launchSettings.json → profiles[*].applicationUrl
- Phoenix: config/dev.exs or config/runtime.exs → port: NNNN
- Spring Boot: src/main/resources/application.{properties,yml} → server.port
- Rails: config/puma.rb → port ENV.fetch("PORT") { N } or literal port N

Falls back to the ecosystem default when the file is missing or malformed.

Python (Django), Go, plain PHP, and Laravel are unchanged — none has a
canonical config file; ports are CLI args or hardcoded in source.
detectLanguage() and its LANGUAGE_DETECTORS table were never called from
the install path. globExists() and detectKotlin() were the only pieces
still used after wiring up the dotnet/kotlin detect() overrides — both
are caller-specific enough to inline:

- dotnet/index.ts gets hasCsproj() (6 lines, readdirSync + endsWith)
- kotlin/index.ts gets isKotlinProject() (handles kts, gradle, pom.xml)
- The Language type moves into framework-config.ts where it is consumed

Net: one fewer module, no lost functionality.
@nicknisi nicknisi merged commit bd9e068 into main Apr 23, 2026
5 checks passed
@nicknisi nicknisi deleted the nicknisi/django-issue branch April 23, 2026 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant