Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions packages/commons/docs-loader/src/readonly-docs-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,14 @@ const createGetPrunedApiCached = (domainKey: string, cacheConfig: Required<Cache
if (cached != null) {
const metadata = await getMetadata(cacheConfig)(domainKey);
const dynamicIr = await getDynamicIr(cacheConfig)(metadata.org, metadata.domain, id);
return await backfillSnippets(cached, dynamicIr, await flagsPromise);
const flags = await flagsPromise;
const settings = await getSettings(cacheConfig)(domainKey);
return await backfillSnippets({
apiDefinition: cached,
dynamicIr,
httpSnippets: settings.httpSnippets ?? flags.isHttpSnippetsEnabled,
alwaysEnableJavaScriptFetch: flags.alwaysEnableJavaScriptFetch
});
}
}
} catch (error) {
Comment on lines +478 to 488
Copy link

Choose a reason for hiding this comment

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

Potential bug: The revalidation route does not call backfillSnippets, unlike the fresh API load path, causing inconsistent HTTP snippet generation depending on cache state.
  • Description: The createGetPrunedApiCached function was updated to call backfillSnippets to enrich API definitions with HTTP snippets. However, the corresponding revalidation route was not updated and does not call backfillSnippets. This creates a data inconsistency where API documentation will have HTTP snippets on a fresh load but will be missing them when served from a revalidated cache. This leads to an inconsistent user experience where snippets appear or disappear depending on the cache state, violating an explicit repository guideline to keep these two code paths in sync.

  • Suggested fix: Update the revalidation route to also call backfillSnippets when creating the pruned API definition. This will ensure that both the fresh load path and the revalidation path apply the same snippet enrichment logic, maintaining data consistency across cache states.
    severity: 0.75, confidence: 0.95

Did we get this right? 👍 / 👎 to inform future reviews.

Expand All @@ -500,7 +507,14 @@ const createGetPrunedApiCached = (domainKey: string, cacheConfig: Required<Cache
}
const metadata = await getMetadata(cacheConfig)(domainKey);
const dynamicIr = await getDynamicIr(cacheConfig)(metadata.org, metadata.domain, id);
return backfillSnippets(pruned, dynamicIr, await flagsPromise);
const settings = await getSettings(cacheConfig)(domainKey);
const flags = await flagsPromise;
return backfillSnippets({
apiDefinition: pruned,
dynamicIr,
httpSnippets: settings.httpSnippets ?? flags.isHttpSnippetsEnabled,
alwaysEnableJavaScriptFetch: flags.alwaysEnableJavaScriptFetch
});
},
[domainKey, cacheSeed(), cacheConfig.cacheKeySuffix],
{ tags: [domainKey, "api"] }
Expand Down Expand Up @@ -739,7 +753,7 @@ const getSettings = (cacheConfig: Required<CacheConfig>) =>
defaultSearchFilters: settings?.defaultSearchFilters ?? false,
disableSearch: settings?.disableSearch ?? false,
hide404Page: settings?.hide404Page ?? false,
httpSnippets: settings?.httpSnippets ?? false,
httpSnippets: settings?.httpSnippets ?? undefined,
searchText: settings?.searchText ?? "Search"
};
});
Expand Down
2 changes: 1 addition & 1 deletion packages/commons/docs-server/src/auth/getAuthState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { type PreviewUrlAuth, getAuthEdgeConfig, getPreviewUrlAuthConfig } from

import { isLocal } from "../isLocal";
import { isSelfHosted } from "../isSelfHosted";
import { safeVerifyFernJWTConfig } from "./FernJWT";
import { getAllowedRedirectUrls } from "./allowed-redirects";
import { getOAuth2AuthorizationUrl } from "./oauth2";
import { preferPreview } from "./origin";
Expand All @@ -18,6 +17,7 @@ import { getReturnToQueryParam } from "./return-to";
import { getWebflowAuthorizationUrl } from "./webflow";
import { getWorkosSSOAuthorizationUrl } from "./workos";
import { handleWorkosAuth } from "./workos-handler";
import { safeVerifyFernJWTConfig } from "./FernJWT";

export type AuthPartner = "workos" | "ory" | "webflow" | "custom" | string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,127 @@ dataTask.resume()",
}
`;

exports[`backfillSnippets > should backfill snippets with just ruby http snippets 1`] = `
{
"ruby": [
{
"code": "require 'uri'
require 'net/http'

url = URI("https://api.example.com/v1/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\\n \\"RecordCount\\": 50,\\n \\"DocumentSearchParams\\": {\\n \\"SearchTerms\\": {\\n \\"All\\": [\\n \\"data security\\"\\n ],\\n \\"Any\\": [\\n \\"cyberattack\\",\\n \\"breach\\"\\n ],\\n \\"None\\": [\\n \\"ransomware\\"\\n ]\\n },\\n \\"DocumentDateRangeStart\\": \\"2023-01-01T00:00:00Z\\",\\n \\"DocumentDateRangeEnd\\": \\"2023-12-31T23:59:59Z\\"\\n }\\n}"

response = http.request(request)
puts response.read_body",
"description": undefined,
"generated": true,
"install": undefined,
"language": "ruby",
"name": undefined,
},
],
}
`;

exports[`backfillSnippets > should backfill snippets with no http snippets 1`] = `
{
"curl": [
{
"code": "curl -X POST https://api.example.com/v1/ \\
-H "Content-Type: application/json" \\
-d '{
"RecordCount": 50,
"DocumentSearchParams": {
"SearchTerms": {
"All": [
"data security"
],
"Any": [
"cyberattack",
"breach"
],
"None": [
"ransomware"
]
},
"DocumentDateRangeStart": "2023-01-01T00:00:00Z",
"DocumentDateRangeEnd": "2023-12-31T23:59:59Z"
}
}'",
"description": undefined,
"generated": true,
"install": undefined,
"language": "curl",
"name": undefined,
},
],
}
`;

exports[`backfillSnippets > should backfill snippets with ruby and curl http snippets 1`] = `
{
"curl": [
{
"code": "curl -X POST https://api.example.com/v1/ \\
-H "Content-Type: application/json" \\
-d '{
"RecordCount": 50,
"DocumentSearchParams": {
"SearchTerms": {
"All": [
"data security"
],
"Any": [
"cyberattack",
"breach"
],
"None": [
"ransomware"
]
},
"DocumentDateRangeStart": "2023-01-01T00:00:00Z",
"DocumentDateRangeEnd": "2023-12-31T23:59:59Z"
}
}'",
"description": undefined,
"generated": true,
"install": undefined,
"language": "curl",
"name": undefined,
},
],
"ruby": [
{
"code": "require 'uri'
require 'net/http'

url = URI("https://api.example.com/v1/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\\n \\"RecordCount\\": 50,\\n \\"DocumentSearchParams\\": {\\n \\"SearchTerms\\": {\\n \\"All\\": [\\n \\"data security\\"\\n ],\\n \\"Any\\": [\\n \\"cyberattack\\",\\n \\"breach\\"\\n ],\\n \\"None\\": [\\n \\"ransomware\\"\\n ]\\n },\\n \\"DocumentDateRangeStart\\": \\"2023-01-01T00:00:00Z\\",\\n \\"DocumentDateRangeEnd\\": \\"2023-12-31T23:59:59Z\\"\\n }\\n}"

response = http.request(request)
puts response.read_body",
"description": undefined,
"generated": true,
"install": undefined,
"language": "ruby",
"name": undefined,
},
],
}
`;

exports[`backfillSnippets > should skip head method for dynamic snippets 1`] = `
{
"csharp": [
Expand Down
Loading