Skip to content

feat(cli): add --id flag for stable preview URLs in docs generation#13660

Merged
kennyderek merged 9 commits intomainfrom
devin/1773780916-named-preview-id
Mar 18, 2026
Merged

feat(cli): add --id flag for stable preview URLs in docs generation#13660
kennyderek merged 9 commits intomainfrom
devin/1773780916-named-preview-id

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 18, 2026

Description

Adds --id <name> flag to fern generate --docs --preview so that preview URLs remain stable across repeated runs. Instead of generating a random UUID for each preview, the provided ID is used as the domain identifier, allowing subsequent runs with the same --id to overwrite the previous preview.

Companion FDR PR: fern-api/fern-platform#8742 (merged) — adds previewId to the startDocsPreviewRegister schema and handler.

Changes Made

  • cli.ts: Add --id string option to the generate command with validation requiring --preview and --docs
  • generateDocsWorkspace.ts:
    • Add buildPreviewDomain() that replicates server-side truncateDomainName logic to predict the preview URL
    • When --id is provided (non-CI, no --force), check FDR metadata via getDocsUrlMetadata (using FdrAPI.Url() branded type) to see if URL already exists and prompt for overwrite confirmation
  • publishDocs.ts: Pass previewId through to startDocsPreviewRegister API call (uses as cast — see review notes)
  • runRemoteGenerationForDocsWorkspace.ts: Thread previewId parameter through the call chain
  • LegacyDocsPublisher.ts: Pass previewId: undefined to match updated function signature
  • versions.yml: Add v4.35.0 changelog entry
  • pnpm-workspace.yaml: Upgrade @fern-api/fdr-sdk catalog entry to 1.1.13-c1ad12a2b8

Updates Since Last Revision

  • Upgraded @fern-api/fdr-sdk catalog entry from 0.145.12-b50d999d1 to 1.1.13-c1ad12a2b8 (published after fern-platform#8742 merged)
  • The FdrClient wrapper still uses old Fern-generated types that lack previewId, so the as cast in publishDocs.ts remains necessary until the client is migrated to use oRPC types for write methods
  • Manual testing with fern-dev:build confirmed the feature works end-to-end against the dev stack smoke-test project — preview published successfully to https://smoke-test-preview-my-test-preview.docs.dev.buildwithfern.com

Important Review Notes

  1. SDK type cast: previewId is not yet in the FDR SDK's StartDocsPreviewRegisterRequestV2 type (the FdrClient wrapper hasn't been migrated to oRPC for write methods), so the request uses as DocsV2Write.StartDocsPreviewRegisterRequestV2. Manual testing confirmed the Fern-generated SDK passes unknown properties through in the JSON body — previewId successfully reached the server and the named preview URL was generated.

  2. Hardcoded DOMAIN_SUFFIX: buildPreviewDomain hardcodes "docs.buildwithfern.com" which won't match dev/staging environments. The overwrite confirmation prompt won't fire in those environments (confirmed during testing). Production behavior is correct.

  3. Duplicated truncation logic: buildPreviewDomain mirrors the server's truncateDomainName. If the server logic changes, these will drift.

  4. pnpm catalog vs override mismatch: The pnpm-workspace.yaml catalog now has @fern-api/fdr-sdk: 1.1.13-c1ad12a2b8, but package.json pnpm.overrides still pins @fern-api/fdr-sdk: 0.145.12-b50d999d1. The override exists because the new SDK version has breaking type changes in FdrClient constructor (e.g. token type changed) that affect other packages like @fern-api/core. Updating the override is a separate task.

Human Review Checklist

  • Confirm Fern SDK serialization passes unknown properties (confirmed via manual testing — previewId delivered successfully)
  • Merge fern-platform#8742 (merged)
  • Decide if hardcoded DOMAIN_SUFFIX is acceptable or should be derived from config/environment
  • Review pnpm catalog vs override version mismatch — acceptable as-is or should both be aligned?

Testing

  • pnpm run check (biome) passes
  • CI green (compile, lint, biome, depcheck, test, test-ete, seed tests)
  • Manual testing with fern-dev:build — published named preview to dev stack successfully
  • Unit tests added/updated

Link to Devin session: https://app.devin.ai/sessions/d3670821970e4e1687c12f99240e043e

Co-Authored-By: kenny <kenny@buildwithfern.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit in Settings → Usage.

Once credits are available, reopen this pull request to trigger a review.

devin-ai-integration bot and others added 4 commits March 18, 2026 16:34
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
Comment on lines +24 to +26
if (fullDomain.length <= SUBDOMAIN_LIMIT) {
return fullDomain;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect subdomain length validation. Line 24 compares the full domain length (including .docs.buildwithfern.com) against SUBDOMAIN_LIMIT (62), but line 29 treats SUBDOMAIN_LIMIT as the maximum length of just the subdomain part. This causes the truncation logic to trigger at the wrong threshold.

The subdomain part ${orgId}-preview-${previewId} should be limited to 63 characters (DNS label limit), not the full domain. Fix:

const subdomain = `${orgId}-preview-${previewId}`;
if (subdomain.length <= SUBDOMAIN_LIMIT) {
    return `${subdomain}.${DOMAIN_SUFFIX}`;
}
Suggested change
if (fullDomain.length <= SUBDOMAIN_LIMIT) {
return fullDomain;
}
const subdomain = `${orgId}-preview-${previewId}`;
if (subdomain.length <= SUBDOMAIN_LIMIT) {
return `${subdomain}.${DOMAIN_SUFFIX}`;
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the mismatch between the full domain vs subdomain comparison — however, the server-side truncateDomainName in getDocsWriteV2Service.ts has the exact same logic:

const subdomainLimit = 62;
const fullDomain = `${orgId}-preview-${docsRegistrationId}.${domainSuffix}`;

if (fullDomain.length <= subdomainLimit) {
    return fullDomain;
}

The CLI intentionally mirrors this so the predicted URL matches what the server produces. Fixing only the CLI side would cause a mismatch where the CLI checks one URL but the server generates a different one.

If this should be fixed, it should be fixed on both sides together (and is pre-existing, not introduced by this PR).

devin-ai-integration bot and others added 4 commits March 18, 2026 18:04
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
Co-Authored-By: kenny <kenny@buildwithfern.com>
@kennyderek kennyderek merged commit 2d2389d into main Mar 18, 2026
89 checks passed
@kennyderek kennyderek deleted the devin/1773780916-named-preview-id branch March 18, 2026 20:49
HoaX7 pushed a commit to HoaX7/fern that referenced this pull request Mar 25, 2026
…ern-api#13660)

* feat: add --id flag for stable preview URLs in docs generation

Co-Authored-By: kenny <kenny@buildwithfern.com>

* fix: use type assertion for previewId until SDK is republished

Co-Authored-By: kenny <kenny@buildwithfern.com>

* fix: add missing previewId parameter to LegacyDocsPublisher

Co-Authored-By: kenny <kenny@buildwithfern.com>

* fix: use FdrAPI.Url branded type for getDocsUrlMetadata call

Co-Authored-By: kenny <kenny@buildwithfern.com>

* fix: update comment explaining type assertion for previewId

Co-Authored-By: kenny <kenny@buildwithfern.com>

* fix: format publishDocs.ts to satisfy biome

Co-Authored-By: kenny <kenny@buildwithfern.com>

* chore: upgrade @fern-api/fdr-sdk to 1.1.13-c1ad12a2b8

Co-Authored-By: kenny <kenny@buildwithfern.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: kenny <kenny@buildwithfern.com>
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