Dexa APIv0.5.0

Naming

Why the generated packages are named after the organization, and how to fix it.

What the generators produce today#

Language Package name Manifest
TypeScript sources only, no package.json missing
Python sources only, no pyproject.toml missing
Ruby dsainvg dsainvg.gemspec
Rust dexa-ai-sdk Cargo.toml
Java org.dsainvg maintained in templates/sdk-java/pom.xml
.NET DexaAiSdk DexaAiSdk.csproj

Why#

Fern derives the SDK's package identity from the API name. This project was created with

bashfern init --api --org dsainvg --openapi contracts/openapi.yaml

which registers the API under the organization and leaves it without a name of its own, so every generator falls back to the organization identifier. dsainvg, dexa-ai-sdk and DexaAiSdk are all that fallback.

The three generators that need a package name to emit a manifest at all, TypeScript, Python and Java, fail differently as a result: they write sources and skip the manifest. The Python generator refuses to start if handed a key it does not recognise, so a wrong key such as package-name fails the generator outright, while package_name is accepted and still leaves the output without a manifest.

fern.config.json cannot fix this. It accepts only organization and version; projectId, name, apiId, api-id, project-id, project, apiName and api-name are all rejected as unrecognized keys.

The fix#

Give the API a name in Fern, which means signing in and creating or renaming the API in the Fern dashboard, or re-running fern init against a named API:

bashfern login
fern init --api --org dsainvg --openapi fern/openapi/openapi.yml

Once the API is named, set the package name for each generator in fern/generators.yml and regenerate. The manifests and the names follow from the contract's info.title, Dexa API.

What this does not affect#

Working around it#

The three clients are still published and usable. Their package manifests are maintained here rather than in packages/, because Fern wipes each output directory before it generates, so anything written inside packages/ by hand is deleted on the next run.

The manifests live in templates/sdk-ts/ and templates/sdk-py/, with __VERSION__ where the version goes, and scripts/write-manifests.mjs renders them into packages/ after generation with info.version from the contract. npm run fern:generate calls it automatically, so the manifests can never drift from the contract version.

File Purpose
templates/sdk-ts/package.json npm package: name, version, exports, build scripts
templates/sdk-ts/tsconfig.json compiler options for the generated sources
templates/sdk-ts/tsconfig.build.json build config emitting dist/ with declarations
templates/sdk-py/pyproject.toml PyPI package: name, version, dependencies, packaging

Because Python's generated tree is flat, pyproject.toml maps the whole directory to one package and lists each subpackage, otherwise setuptools builds a wheel with only the top-level modules. The import name is dexa_ai_sdk, which is what the generator's own docstrings, User-Agent header and tests reference.

The Ruby gem needs no equivalent: Fern generates custom.gemspec.rb as a documented hook for exactly this, so the gem's name and metadata are set there and protected with .fernignore.

Do not add .fernignore to packages/sdk-ts or packages/sdk-py: Fern runs git reset -- on the ignored paths with NUL-separated arguments, which fails on Linux runners with ERR_INVALID_ARG_VALUE.