@fern-api/fern-api-dev 5.23.3-378-g4009024e80d → 5.23.3-382-g24ea8784553

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli.cjs +469 -107
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -589242,7 +589242,7 @@ var GeneratorName = {
589242
589242
  STOPLIGHT: "fernapi/fern-stoplight",
589243
589243
  POSTMAN: "fernapi/fern-postman",
589244
589244
  OPENAPI_PYTHON_CLIENT: "fernapi/openapi-python-client",
589245
- CLI: "fernapi/fern-cli-generator"
589245
+ CLI: "fernapi/fern-cli"
589246
589246
  };
589247
589247
 
589248
589248
  // ../configuration-loader/lib/generators-yml/addGenerator.js
@@ -669533,7 +669533,7 @@ var AccessTokenPosthogManager = class {
669533
669533
  properties: {
669534
669534
  ...event,
669535
669535
  ...event.properties,
669536
- version: "5.23.3-378-g4009024e80d",
669536
+ version: "5.23.3-382-g24ea8784553",
669537
669537
  usingAccessToken: true,
669538
669538
  ...getRunIdProperties()
669539
669539
  }
@@ -669597,7 +669597,7 @@ var UserPosthogManager = class {
669597
669597
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
669598
669598
  event: "CLI",
669599
669599
  properties: {
669600
- version: "5.23.3-378-g4009024e80d",
669600
+ version: "5.23.3-382-g24ea8784553",
669601
669601
  ...event,
669602
669602
  ...event.properties,
669603
669603
  usingAccessToken: false,
@@ -675157,7 +675157,7 @@ var DOCKER_IMAGE_TO_GENERATOR_ID = {
675157
675157
  "fernapi/fern-swift-model": "swift-model",
675158
675158
  "fernapi/fern-postman": "postman",
675159
675159
  "fernapi/fern-openapi": "openapi",
675160
- "fernapi/fern-cli-generator": "cli"
675160
+ "fernapi/fern-cli": "cli"
675161
675161
  };
675162
675162
  var DOCKER_IMAGE_TO_CHANGELOG_URL = {
675163
675163
  "fernapi/fern-typescript-sdk": "https://buildwithfern.com/learn/sdks/generators/typescript/changelog",
@@ -676976,7 +676976,7 @@ var MINIMUM_SUPPORTED_IR_VERSION = 53;
676976
676976
 
676977
676977
  // ../generation/ir-migrations/lib/generatorVersionMap.js
676978
676978
  var GENERATOR_MINIMUM_VERSIONS = {
676979
- "fernapi/fern-cli-generator": "0.0.1",
676979
+ "fernapi/fern-cli": "0.0.1",
676980
676980
  "fernapi/fern-csharp-model": "0.0.2",
676981
676981
  "fernapi/fern-csharp-sdk": "0.5.0",
676982
676982
  "fernapi/fern-express": "0.17.3",
@@ -817800,6 +817800,106 @@ init_lib4();
817800
817800
  // ../docs-resolver/lib/index.js
817801
817801
  init_lib41();
817802
817802
 
817803
+ // ../docs-resolver/lib/applyTranslatedApiTitlesToNavTree.js
817804
+ init_lib4();
817805
+ init_js();
817806
+ function applyTranslatedApiTitlesToNavTree(root6, baseApis, translatedApis) {
817807
+ const mapsByApiId = /* @__PURE__ */ new Map();
817808
+ for (const [apiId, translatedApi] of Object.entries(translatedApis)) {
817809
+ const holder = navigation_exports.ApiDefinitionHolder.create(translatedApi);
817810
+ const endpoints = /* @__PURE__ */ new Map();
817811
+ for (const [id2, endpoint3] of holder.endpoints) {
817812
+ if (endpoint3.name != null && endpoint3.name.length > 0) {
817813
+ endpoints.set(id2, endpoint3.name);
817814
+ }
817815
+ }
817816
+ const webhooks2 = /* @__PURE__ */ new Map();
817817
+ for (const [id2, webhook] of holder.webhooks) {
817818
+ if (webhook.name != null && webhook.name.length > 0) {
817819
+ webhooks2.set(id2, webhook.name);
817820
+ }
817821
+ }
817822
+ const webSockets = /* @__PURE__ */ new Map();
817823
+ for (const [id2, webSocket] of holder.webSockets) {
817824
+ if (webSocket.name != null && webSocket.name.length > 0) {
817825
+ webSockets.set(id2, webSocket.name);
817826
+ }
817827
+ }
817828
+ const graphql4 = /* @__PURE__ */ new Map();
817829
+ for (const [id2, operation] of holder.graphqlOperations) {
817830
+ const name2 = operation.displayName ?? operation.name;
817831
+ if (name2 != null && name2.length > 0) {
817832
+ graphql4.set(id2, name2);
817833
+ }
817834
+ }
817835
+ const packagesByBaseTitle = /* @__PURE__ */ new Map();
817836
+ const baseApi = baseApis[apiId];
817837
+ if (baseApi != null) {
817838
+ for (const [subpackageId, translatedSubpackage] of Object.entries(translatedApi.subpackages)) {
817839
+ const baseSubpackage = baseApi.subpackages[subpackageId];
817840
+ if (baseSubpackage == null) {
817841
+ continue;
817842
+ }
817843
+ const baseTitle = baseSubpackage.displayName ?? titleCase(baseSubpackage.name);
817844
+ const translatedTitle = translatedSubpackage.displayName ?? titleCase(translatedSubpackage.name);
817845
+ if (baseTitle !== translatedTitle) {
817846
+ packagesByBaseTitle.set(baseTitle, translatedTitle);
817847
+ }
817848
+ }
817849
+ }
817850
+ mapsByApiId.set(apiId, { endpoints, webhooks: webhooks2, webSockets, graphql: graphql4, packagesByBaseTitle });
817851
+ }
817852
+ const clone5 = structuredClone(root6);
817853
+ const visit5 = (node4) => {
817854
+ if (node4 == null || typeof node4 !== "object") {
817855
+ return;
817856
+ }
817857
+ if (Array.isArray(node4)) {
817858
+ for (const item of node4) {
817859
+ visit5(item);
817860
+ }
817861
+ return;
817862
+ }
817863
+ const obj = node4;
817864
+ const apiDefinitionId = typeof obj.apiDefinitionId === "string" ? obj.apiDefinitionId : void 0;
817865
+ const maps = apiDefinitionId != null ? mapsByApiId.get(apiDefinitionId) : void 0;
817866
+ if (maps != null) {
817867
+ const type8 = obj.type;
817868
+ if (type8 === "endpoint" && typeof obj.endpointId === "string") {
817869
+ const translated = maps.endpoints.get(obj.endpointId);
817870
+ if (translated != null) {
817871
+ obj.title = translated;
817872
+ }
817873
+ } else if (type8 === "webhook" && typeof obj.webhookId === "string") {
817874
+ const translated = maps.webhooks.get(obj.webhookId);
817875
+ if (translated != null) {
817876
+ obj.title = translated;
817877
+ }
817878
+ } else if (type8 === "webSocket" && typeof obj.webSocketId === "string") {
817879
+ const translated = maps.webSockets.get(obj.webSocketId);
817880
+ if (translated != null) {
817881
+ obj.title = translated;
817882
+ }
817883
+ } else if (type8 === "graphql" && typeof obj.graphqlOperationId === "string") {
817884
+ const translated = maps.graphql.get(obj.graphqlOperationId);
817885
+ if (translated != null) {
817886
+ obj.title = translated;
817887
+ }
817888
+ } else if (type8 === "apiPackage" && typeof obj.title === "string") {
817889
+ const translated = maps.packagesByBaseTitle.get(obj.title);
817890
+ if (translated != null) {
817891
+ obj.title = translated;
817892
+ }
817893
+ }
817894
+ }
817895
+ for (const value2 of Object.values(obj)) {
817896
+ visit5(value2);
817897
+ }
817898
+ };
817899
+ visit5(clone5);
817900
+ return clone5;
817901
+ }
817902
+
817803
817903
  // ../docs-resolver/lib/applyTranslatedFrontmatterToNavTree.js
817804
817904
  var import_gray_matter5 = __toESM(require_gray_matter(), 1);
817805
817905
  function parseFrontmatterOverrides(markdown) {
@@ -826340,7 +826440,8 @@ var DocsDefinitionResolver = class {
826340
826440
  uploadFiles;
826341
826441
  registerApi;
826342
826442
  targetAudiences;
826343
- constructor({ domain: domain3, docsWorkspace, ossWorkspaces, apiWorkspaces, taskContext, editThisPage, uploadFiles: uploadFiles2 = defaultUploadFiles, registerApi: registerApi2 = defaultRegisterApi, targetAudiences }) {
826443
+ buildTranslatedApiDefinitions;
826444
+ constructor({ domain: domain3, docsWorkspace, ossWorkspaces, apiWorkspaces, taskContext, editThisPage, uploadFiles: uploadFiles2 = defaultUploadFiles, registerApi: registerApi2 = defaultRegisterApi, targetAudiences, buildTranslatedApiDefinitions = false }) {
826344
826445
  this.domain = domain3;
826345
826446
  this.docsWorkspace = docsWorkspace;
826346
826447
  this.ossWorkspaces = ossWorkspaces;
@@ -826350,6 +826451,7 @@ var DocsDefinitionResolver = class {
826350
826451
  this.uploadFiles = uploadFiles2;
826351
826452
  this.registerApi = registerApi2;
826352
826453
  this.targetAudiences = targetAudiences;
826454
+ this.buildTranslatedApiDefinitions = buildTranslatedApiDefinitions;
826353
826455
  }
826354
826456
  #idgen = NodeIdGenerator2.init();
826355
826457
  /**
@@ -826459,6 +826561,13 @@ var DocsDefinitionResolver = class {
826459
826561
  getDocsWorkspacePath() {
826460
826562
  return this.docsWorkspace.absoluteFilePath;
826461
826563
  }
826564
+ /**
826565
+ * Returns per-locale translated API definitions, keyed by locale then by the base
826566
+ * `apiDefinitionId`. Must be called after `resolve()`.
826567
+ */
826568
+ getTranslatedApiSpecs() {
826569
+ return this.translatedApiSpecs;
826570
+ }
826462
826571
  getDocsTranslationsConfig() {
826463
826572
  const translations = this.parsedDocsConfig.translations;
826464
826573
  if (translations == null || translations.length === 0) {
@@ -826484,6 +826593,12 @@ var DocsDefinitionResolver = class {
826484
826593
  referencedMarkdownFiles = [];
826485
826594
  pendingApiRegistrations = [];
826486
826595
  pendingApiCounter = 0;
826596
+ /**
826597
+ * Per-locale translated API definitions, keyed by locale then by the base
826598
+ * `apiDefinitionId`. Populated during {@link resolve} when an API section has
826599
+ * a translated OpenAPI spec under `translations/<locale>/apis/<apiName>/`.
826600
+ */
826601
+ translatedApiSpecs = /* @__PURE__ */ new Map();
826487
826602
  async resolve() {
826488
826603
  const resolveStartTime = performance.now();
826489
826604
  const startMemory = process.memoryUsage();
@@ -826638,6 +826753,25 @@ var DocsDefinitionResolver = class {
826638
826753
  graphqlTypes: pending.graphqlTypes
826639
826754
  });
826640
826755
  updateApiDefinitionIdInTree(pending.apiReferenceNode, pending.tempApiDefinitionId, realApiDefinitionId);
826756
+ if (pending.translatedIrsByLocale != null) {
826757
+ for (const [locale, translatedIr] of pending.translatedIrsByLocale) {
826758
+ this.resolveLinksInIrDocs(translatedIr, markdownFilesToPathName);
826759
+ let localeMap = this.translatedApiSpecs.get(locale);
826760
+ if (localeMap == null) {
826761
+ localeMap = /* @__PURE__ */ new Map();
826762
+ this.translatedApiSpecs.set(locale, localeMap);
826763
+ }
826764
+ localeMap.set(realApiDefinitionId, {
826765
+ ir: translatedIr,
826766
+ snippetsConfig: pending.snippetsConfig,
826767
+ playgroundConfig: pending.playgroundConfig,
826768
+ apiName: pending.apiName,
826769
+ graphqlOperations: pending.graphqlOperations,
826770
+ graphqlTypes: pending.graphqlTypes,
826771
+ workspace: pending.workspace
826772
+ });
826773
+ }
826774
+ }
826641
826775
  }
826642
826776
  const deferredTime = performance.now() - deferredStart;
826643
826777
  this.taskContext.logger.debug(`Processed deferred API registrations in ${deferredTime.toFixed(0)}ms`);
@@ -826996,6 +827130,112 @@ Learn more about project structure:
826996
827130
  https://buildwithfern.com/learn/docs/getting-started/project-structure#api-definitions` : "Failed to load API Definition referenced in docs.\nLearn more about project structure:\nhttps://buildwithfern.com/learn/docs/getting-started/project-structure#api-definitions";
826997
827131
  throw new CliError({ message: errorMessage, code: CliError.Code.ConfigError });
826998
827132
  }
827133
+ /**
827134
+ * Builds a translated IR for each configured non-default locale whose
827135
+ * `translations/<locale>/apis/<apiName>/` directory contains a translated copy of
827136
+ * the API's OpenAPI spec. The translated spec must be structurally identical to the
827137
+ * base (same paths, operationIds, schema names) so the derived IR lines up 1:1 and
827138
+ * can be keyed by the same `apiDefinitionId`.
827139
+ */
827140
+ async buildTranslatedApiIrs(item, baseOssWorkspace) {
827141
+ const translationsConfig = this.getDocsTranslationsConfig();
827142
+ if (translationsConfig?.translations == null || translationsConfig.translations.length === 0) {
827143
+ return void 0;
827144
+ }
827145
+ const { defaultLocale, translations } = translationsConfig;
827146
+ const fernFolder = this.docsWorkspace.absoluteFilePath;
827147
+ const result = /* @__PURE__ */ new Map();
827148
+ for (const locale of translations) {
827149
+ if (locale === defaultLocale) {
827150
+ continue;
827151
+ }
827152
+ const translatedWorkspace = this.createTranslatedOssWorkspace(baseOssWorkspace, locale, fernFolder);
827153
+ if (translatedWorkspace == null) {
827154
+ continue;
827155
+ }
827156
+ try {
827157
+ const translatedIr = await translatedWorkspace.getIntermediateRepresentation({
827158
+ context: this.taskContext,
827159
+ audiences: item.audiences,
827160
+ enableUniqueErrorsPerEndpoint: true,
827161
+ generateV1Examples: false,
827162
+ logWarnings: false
827163
+ });
827164
+ result.set(locale, translatedIr);
827165
+ this.taskContext.logger.debug(`Built translated API definition for locale "${locale}" (api: ${item.apiName ?? baseOssWorkspace.workspaceName ?? "<default>"})`);
827166
+ } catch (error50) {
827167
+ this.taskContext.logger.warn(`Failed to build translated API definition for locale "${locale}": ${extractErrorMessage(error50)}. Falling back to the default-locale API for this locale.`);
827168
+ }
827169
+ }
827170
+ return result.size > 0 ? result : void 0;
827171
+ }
827172
+ /**
827173
+ * Clones an OSS (OpenAPI) workspace, remapping spec file paths from `apis/<...>` to
827174
+ * `translations/<locale>/apis/<...>` wherever a translated file exists. Returns
827175
+ * `undefined` when no primary spec has a translated counterpart. Override/overlay
827176
+ * files fall back to the base copy when untranslated, keeping structural metadata
827177
+ * (x-fern-* extensions, audiences, etc.) consistent with the base definition.
827178
+ */
827179
+ createTranslatedOssWorkspace(base4, locale, fernFolder) {
827180
+ let hasTranslatedSpec = false;
827181
+ const toTranslatedPath = (absPath, countsAsTranslation) => {
827182
+ const rel2 = relative4(fernFolder, absPath);
827183
+ if (String(rel2).startsWith("..")) {
827184
+ return absPath;
827185
+ }
827186
+ const candidate = join8(fernFolder, RelativeFilePath2.of(`translations/${locale}`), rel2);
827187
+ if ((0, import_fs26.existsSync)(candidate)) {
827188
+ if (countsAsTranslation) {
827189
+ hasTranslatedSpec = true;
827190
+ }
827191
+ return candidate;
827192
+ }
827193
+ return absPath;
827194
+ };
827195
+ const remapOverrides = (overrides) => {
827196
+ if (overrides == null) {
827197
+ return overrides;
827198
+ }
827199
+ if (Array.isArray(overrides)) {
827200
+ return overrides.map((p14) => toTranslatedPath(p14, false));
827201
+ }
827202
+ return toTranslatedPath(overrides, false);
827203
+ };
827204
+ const remapSpec = (spec) => {
827205
+ switch (spec.type) {
827206
+ case "openapi":
827207
+ return {
827208
+ ...spec,
827209
+ absoluteFilepath: toTranslatedPath(spec.absoluteFilepath, true),
827210
+ absoluteFilepathToOverrides: remapOverrides(spec.absoluteFilepathToOverrides),
827211
+ absoluteFilepathToOverlays: spec.absoluteFilepathToOverlays != null ? toTranslatedPath(spec.absoluteFilepathToOverlays, false) : void 0
827212
+ };
827213
+ case "openrpc":
827214
+ case "graphql":
827215
+ return {
827216
+ ...spec,
827217
+ absoluteFilepath: toTranslatedPath(spec.absoluteFilepath, true),
827218
+ absoluteFilepathToOverrides: remapOverrides(spec.absoluteFilepathToOverrides)
827219
+ };
827220
+ default:
827221
+ return spec;
827222
+ }
827223
+ };
827224
+ const translatedSpecs = base4.specs.map((spec) => remapSpec(spec));
827225
+ const translatedAllSpecs = base4.allSpecs.map((spec) => remapSpec(spec));
827226
+ if (!hasTranslatedSpec) {
827227
+ return void 0;
827228
+ }
827229
+ return new OSSWorkspace({
827230
+ allSpecs: translatedAllSpecs,
827231
+ specs: translatedSpecs,
827232
+ generatorsConfiguration: base4.generatorsConfiguration,
827233
+ workspaceName: base4.workspaceName,
827234
+ cliVersion: base4.cliVersion,
827235
+ absoluteFilePath: base4.absoluteFilePath,
827236
+ changelog: base4.changelog
827237
+ });
827238
+ }
826999
827239
  async toRootNode() {
827000
827240
  const slug = navigation_exports.V1.SlugGenerator.init(navigation_exports.slugjoin(this.getDocsBasePath()));
827001
827241
  const id2 = this.#idgen.get("root");
@@ -827414,6 +827654,10 @@ https://buildwithfern.com/learn/docs/getting-started/project-structure#api-defin
827414
827654
  this.parsedDocsConfig.pages[relativePath] = processedContent;
827415
827655
  }
827416
827656
  const apiReferenceNode = node4.get();
827657
+ let translatedIrsByLocale;
827658
+ if (this.buildTranslatedApiDefinitions && openapiWorkspace != null) {
827659
+ translatedIrsByLocale = await this.buildTranslatedApiIrs(item, openapiWorkspace);
827660
+ }
827417
827661
  this.pendingApiRegistrations.push({
827418
827662
  ir: ir11,
827419
827663
  snippetsConfig,
@@ -827423,7 +827667,8 @@ https://buildwithfern.com/learn/docs/getting-started/project-structure#api-defin
827423
827667
  graphqlOperations: graphqlData.operations,
827424
827668
  graphqlTypes: graphqlData.types,
827425
827669
  tempApiDefinitionId,
827426
- apiReferenceNode
827670
+ apiReferenceNode,
827671
+ translatedIrsByLocale
827427
827672
  });
827428
827673
  return apiReferenceNode;
827429
827674
  }
@@ -861038,7 +861283,7 @@ var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
861038
861283
  var LOGS_FOLDER_NAME = "logs";
861039
861284
  var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
861040
861285
  function getCliSource() {
861041
- const version7 = "5.23.3-378-g4009024e80d";
861286
+ const version7 = "5.23.3-382-g24ea8784553";
861042
861287
  return `cli@${version7}`;
861043
861288
  }
861044
861289
  var DebugLogger = class {
@@ -863879,7 +864124,8 @@ async function getPreviewDocsDefinition({ domain: domain3, project, context: con
863879
864124
  translationPages: previousPreviewResult.translationPages,
863880
864125
  translationNavigationOverlays: previousPreviewResult.translationNavigationOverlays,
863881
864126
  collectedFileIds: previousPreviewResult.collectedFileIds,
863882
- docsWorkspacePath: previousPreviewResult.docsWorkspacePath
864127
+ docsWorkspacePath: previousPreviewResult.docsWorkspacePath,
864128
+ translatedApiDefinitions: previousPreviewResult.translatedApiDefinitions
863883
864129
  };
863884
864130
  }
863885
864131
  }
@@ -863908,7 +864154,8 @@ async function getPreviewDocsDefinition({ domain: domain3, project, context: con
863908
864154
  };
863909
864155
  }),
863910
864156
  registerApi: async (opts) => apiCollector.addReferencedAPI(opts),
863911
- targetAudiences: void 0
864157
+ targetAudiences: void 0,
864158
+ buildTranslatedApiDefinitions: true
863912
864159
  });
863913
864160
  const writeDocsDefinition = await resolver2.resolve();
863914
864161
  const dbDocsDefinition = convertDocsDefinitionToDb({
@@ -863951,14 +864198,54 @@ async function getPreviewDocsDefinition({ domain: domain3, project, context: con
863951
864198
  const translationPages = resolver2.getTranslationPages();
863952
864199
  const translationNavigationOverlays = resolver2.getTranslationNavigationOverlays();
863953
864200
  const collectedFileIds = resolver2.getCollectedFileIds();
864201
+ const translatedApiSpecs = resolver2.getTranslatedApiSpecs();
864202
+ let translatedApiDefinitions;
864203
+ if (translatedApiSpecs.size > 0) {
864204
+ translatedApiDefinitions = {};
864205
+ for (const [locale, byApiId] of translatedApiSpecs) {
864206
+ const localeApis = {};
864207
+ for (const [apiDefinitionId, spec] of byApiId) {
864208
+ try {
864209
+ localeApis[apiDefinitionId] = convertTranslatedIrToReadApi(spec, apiDefinitionId, context3);
864210
+ } catch (error50) {
864211
+ context3.logger.warn(`Failed to convert translated API definition "${apiDefinitionId}" for locale "${locale}": ${extractErrorMessage(error50)}. Falling back to the default-locale API.`);
864212
+ }
864213
+ }
864214
+ if (Object.keys(localeApis).length > 0) {
864215
+ translatedApiDefinitions[locale] = localeApis;
864216
+ }
864217
+ }
864218
+ if (Object.keys(translatedApiDefinitions).length === 0) {
864219
+ translatedApiDefinitions = void 0;
864220
+ }
864221
+ }
863954
864222
  return {
863955
864223
  docsDefinition,
863956
864224
  translationPages,
863957
864225
  translationNavigationOverlays,
863958
864226
  collectedFileIds,
863959
- docsWorkspacePath: docsWorkspace.absoluteFilePath
864227
+ docsWorkspacePath: docsWorkspace.absoluteFilePath,
864228
+ translatedApiDefinitions
863960
864229
  };
863961
864230
  }
864231
+ function convertTranslatedIrToReadApi(spec, apiDefinitionId, context3) {
864232
+ const dbApiDefinition = convertAPIDefinitionToDb(convertIrToFdrApi({
864233
+ ir: spec.ir,
864234
+ snippetsConfig: spec.snippetsConfig,
864235
+ playgroundConfig: spec.playgroundConfig,
864236
+ graphqlOperations: spec.graphqlOperations ?? {},
864237
+ graphqlTypes: spec.graphqlTypes ?? {},
864238
+ context: context3,
864239
+ apiNameOverride: spec.apiName
864240
+ }), FdrAPI_exports.ApiDefinitionId(apiDefinitionId), new SDKSnippetHolder({
864241
+ snippetsConfigWithSdkId: {},
864242
+ snippetsBySdkId: {},
864243
+ snippetTemplatesByEndpoint: {},
864244
+ snippetTemplatesByEndpointId: {},
864245
+ snippetsBySdkIdAndEndpointId: {}
864246
+ }));
864247
+ return convertDbAPIDefinitionToRead(dbApiDefinition);
864248
+ }
863962
864249
  async function applyGlobalThemeIfNeeded(docsWorkspace, organization, context3) {
863963
864250
  const themeName = docsWorkspace.config.globalTheme;
863964
864251
  if (themeName == null) {
@@ -864546,15 +864833,22 @@ async function runAppPreviewServer({ initialProject, reloadProject, validateProj
864546
864833
  const RELOAD_DEBOUNCE_MS = 1e3;
864547
864834
  async function computeTranslatedDefinitions(result) {
864548
864835
  const translations = /* @__PURE__ */ new Map();
864549
- const { docsDefinition, translationPages, translationNavigationOverlays, collectedFileIds, docsWorkspacePath } = result;
864550
- if (translationPages == null || Object.keys(translationPages).length === 0) {
864836
+ const { docsDefinition, translationPages, translationNavigationOverlays, translatedApiDefinitions, collectedFileIds, docsWorkspacePath } = result;
864837
+ const hasTranslatedPages = translationPages != null && Object.keys(translationPages).length > 0;
864838
+ const hasTranslatedApis = translatedApiDefinitions != null && Object.keys(translatedApiDefinitions).length > 0;
864839
+ if (!hasTranslatedPages && !hasTranslatedApis) {
864551
864840
  return translations;
864552
864841
  }
864553
864842
  const defaultLocale = docsDefinition.config.translations?.defaultLocale;
864554
- for (const [locale, localePages] of Object.entries(translationPages)) {
864843
+ const localesToBuild = /* @__PURE__ */ new Set([
864844
+ ...Object.keys(translationPages ?? {}),
864845
+ ...Object.keys(translatedApiDefinitions ?? {})
864846
+ ]);
864847
+ for (const locale of localesToBuild) {
864555
864848
  if (locale === defaultLocale) {
864556
864849
  continue;
864557
864850
  }
864851
+ const localePages = translationPages?.[locale] ?? {};
864558
864852
  try {
864559
864853
  const resolveLocalePath = async (filepath) => {
864560
864854
  const relPath = relative4(docsWorkspacePath, filepath);
@@ -864633,8 +864927,14 @@ async function runAppPreviewServer({ initialProject, reloadProject, validateProj
864633
864927
  translatedNavbarLinks = localeNavOverlay.navbarLinks;
864634
864928
  }
864635
864929
  }
864930
+ const localeApis = translatedApiDefinitions?.[locale];
864931
+ const translatedApis = localeApis != null ? { ...docsDefinition.apis, ...localeApis } : docsDefinition.apis;
864932
+ if (localeApis != null && updatedRoot != null) {
864933
+ updatedRoot = applyTranslatedApiTitlesToNavTree(updatedRoot, docsDefinition.apis, localeApis);
864934
+ }
864636
864935
  const translatedDefinition = {
864637
864936
  ...docsDefinition,
864937
+ apis: translatedApis,
864638
864938
  pages: translatedPages,
864639
864939
  config: {
864640
864940
  ...docsDefinition.config,
@@ -864644,7 +864944,7 @@ async function runAppPreviewServer({ initialProject, reloadProject, validateProj
864644
864944
  }
864645
864945
  };
864646
864946
  translations.set(locale, translatedDefinition);
864647
- context3.logger.debug(`Computed translated definition for locale "${locale}"`);
864947
+ context3.logger.debug(`Computed translated definition for locale "${locale}"` + (localeApis != null ? ` (with ${Object.keys(localeApis).length} translated API(s))` : ""));
864648
864948
  } catch (error50) {
864649
864949
  context3.logger.warn(`Failed to compute translation for locale "${locale}": ${String(error50)}`);
864650
864950
  }
@@ -890934,6 +891234,114 @@ async function publishDocs({ token, organization, docsWorkspace, domain: domain3
890934
891234
  token: token.value,
890935
891235
  taskContext: context3
890936
891236
  });
891237
+ const buildTranslatedApiDefinitions = docsWorkspace.config.translations != null && docsWorkspace.config.translations.length > 1;
891238
+ const readApiDefinitionsById = /* @__PURE__ */ new Map();
891239
+ const captureReadApiDefinition = (definition3, apiDefinitionId) => {
891240
+ if (!buildTranslatedApiDefinitions) {
891241
+ return;
891242
+ }
891243
+ try {
891244
+ const dbApiDefinition = convertAPIDefinitionToDb(definition3, FdrAPI_exports.ApiDefinitionId(apiDefinitionId), new SDKSnippetHolder({
891245
+ snippetsConfigWithSdkId: {},
891246
+ snippetsBySdkId: {},
891247
+ snippetTemplatesByEndpoint: {},
891248
+ snippetTemplatesByEndpointId: {},
891249
+ snippetsBySdkIdAndEndpointId: {}
891250
+ }));
891251
+ readApiDefinitionsById.set(apiDefinitionId, convertDbAPIDefinitionToRead(dbApiDefinition));
891252
+ } catch (error50) {
891253
+ context3.logger.debug(`Failed to build read API definition for ${apiDefinitionId} (translated sidebar titles may stay in the default language): ${String(error50)}`);
891254
+ }
891255
+ };
891256
+ const registerApiToFdr = async ({ ir: ir11, snippetsConfig, playgroundConfig, apiName, workspace, graphqlOperations, graphqlTypes }) => {
891257
+ let apiDefinition = convertIrToFdrApi({
891258
+ ir: ir11,
891259
+ snippetsConfig,
891260
+ playgroundConfig,
891261
+ graphqlOperations,
891262
+ graphqlTypes,
891263
+ context: context3,
891264
+ apiNameOverride: apiName
891265
+ });
891266
+ const isSelfHosted = token.value === "dummy";
891267
+ const aiEnhancerConfig = getAIEnhancerConfig(withAiExamples && !isSelfHosted, docsWorkspace.config.aiExamples?.style ?? docsWorkspace.config.experimental?.aiExampleStyleInstructions);
891268
+ if (aiEnhancerConfig) {
891269
+ const sources = workspace?.getSources();
891270
+ const openApiSources = sources?.filter((source2) => source2.type === "openapi").map((source2) => ({
891271
+ absoluteFilePath: source2.absoluteFilePath,
891272
+ absoluteFilePathToOverrides: source2.absoluteFilePathToOverrides
891273
+ }));
891274
+ if (openApiSources == null || openApiSources.length === 0) {
891275
+ context3.logger.debug("Skipping AI example enhancement: no OpenAPI source file paths available");
891276
+ } else {
891277
+ apiDefinition = await enhanceExamplesWithAI(apiDefinition, aiEnhancerConfig, context3, token, organization, openApiSources);
891278
+ }
891279
+ }
891280
+ let dynamicIRsByLanguage;
891281
+ let languagesWithExistingSdkDynamicIr = /* @__PURE__ */ new Set();
891282
+ if (Object.keys(snippetsConfig).length === 0) {
891283
+ context3.logger.debug(`No snippets configuration defined, skipping snippet generation...`);
891284
+ } else if (!disableDynamicSnippets) {
891285
+ const existingSdkDynamicIrs = await checkAndDownloadExistingSdkDynamicIRs({
891286
+ fdr,
891287
+ workspace,
891288
+ organization,
891289
+ context: context3,
891290
+ snippetsConfig
891291
+ });
891292
+ if (existingSdkDynamicIrs && Object.keys(existingSdkDynamicIrs).length > 0) {
891293
+ dynamicIRsByLanguage = existingSdkDynamicIrs;
891294
+ languagesWithExistingSdkDynamicIr = new Set(Object.keys(existingSdkDynamicIrs));
891295
+ context3.logger.debug(`Using existing SDK dynamic IRs for: ${Object.keys(existingSdkDynamicIrs).join(", ")}`);
891296
+ }
891297
+ const generatedDynamicIRs = await generateLanguageSpecificDynamicIRs({
891298
+ workspace,
891299
+ organization,
891300
+ context: context3,
891301
+ snippetsConfig,
891302
+ skipLanguages: languagesWithExistingSdkDynamicIr
891303
+ });
891304
+ if (generatedDynamicIRs) {
891305
+ dynamicIRsByLanguage = {
891306
+ ...dynamicIRsByLanguage,
891307
+ ...generatedDynamicIRs
891308
+ };
891309
+ }
891310
+ }
891311
+ let response;
891312
+ try {
891313
+ response = await fdr.api.register.registerApiDefinition({
891314
+ orgId: FdrAPI_exports.OrgId(organization),
891315
+ apiId: FdrAPI_exports.ApiId(apiName ?? getOriginalName(ir11.apiName)),
891316
+ definition: apiDefinition,
891317
+ dynamicIRs: dynamicIRsByLanguage
891318
+ });
891319
+ } catch (error50) {
891320
+ const errorDetails = extractErrorDetails(error50);
891321
+ context3.logger.error(`FDR registerApiDefinition failed. Error details:
891322
+ ${JSON.stringify(errorDetails, void 0, 2)}`);
891323
+ if (apiName != null) {
891324
+ return context3.failAndThrow(`Failed to publish docs because API definition (${apiName}) could not be uploaded. Please contact support@buildwithfern.com`, errorDetails, { code: CliError.Code.NetworkError });
891325
+ } else {
891326
+ return context3.failAndThrow(`Failed to publish docs because API definition could not be uploaded. Please contact support@buildwithfern.com`, errorDetails, { code: CliError.Code.NetworkError });
891327
+ }
891328
+ }
891329
+ context3.logger.debug(`Registered API Definition ${apiName}: ${response.apiDefinitionId}`);
891330
+ if (response.dynamicIRs && dynamicIRsByLanguage) {
891331
+ if (skipUpload) {
891332
+ context3.logger.debug("Skip-upload mode: skipping dynamic IR uploads");
891333
+ } else {
891334
+ await uploadDynamicIRs({
891335
+ dynamicIRs: dynamicIRsByLanguage,
891336
+ dynamicIRUploadUrls: response.dynamicIRs,
891337
+ context: context3,
891338
+ apiId: response.apiDefinitionId
891339
+ });
891340
+ }
891341
+ }
891342
+ captureReadApiDefinition(apiDefinition, response.apiDefinitionId);
891343
+ return response.apiDefinitionId;
891344
+ };
890937
891345
  const resolver2 = new DocsDefinitionResolver({
890938
891346
  domain: domain3,
890939
891347
  docsWorkspace: effectiveWorkspace,
@@ -891057,94 +891465,8 @@ async function publishDocs({ token, organization, docsWorkspace, domain: domain3
891057
891465
  return convertToFilePathPairs(startDocsRegisterResponse.uploadUrls, docsWorkspace.absoluteFilePath, sanitizedToAbsoluteMap);
891058
891466
  }
891059
891467
  },
891060
- registerApi: async ({ ir: ir11, snippetsConfig, playgroundConfig, apiName, workspace, graphqlOperations, graphqlTypes }) => {
891061
- let apiDefinition = convertIrToFdrApi({
891062
- ir: ir11,
891063
- snippetsConfig,
891064
- playgroundConfig,
891065
- graphqlOperations,
891066
- graphqlTypes,
891067
- context: context3,
891068
- apiNameOverride: apiName
891069
- });
891070
- const isSelfHosted = token.value === "dummy";
891071
- const aiEnhancerConfig = getAIEnhancerConfig(withAiExamples && !isSelfHosted, docsWorkspace.config.aiExamples?.style ?? docsWorkspace.config.experimental?.aiExampleStyleInstructions);
891072
- if (aiEnhancerConfig) {
891073
- const sources = workspace?.getSources();
891074
- const openApiSources = sources?.filter((source2) => source2.type === "openapi").map((source2) => ({
891075
- absoluteFilePath: source2.absoluteFilePath,
891076
- absoluteFilePathToOverrides: source2.absoluteFilePathToOverrides
891077
- }));
891078
- if (openApiSources == null || openApiSources.length === 0) {
891079
- context3.logger.debug("Skipping AI example enhancement: no OpenAPI source file paths available");
891080
- } else {
891081
- apiDefinition = await enhanceExamplesWithAI(apiDefinition, aiEnhancerConfig, context3, token, organization, openApiSources);
891082
- }
891083
- }
891084
- let dynamicIRsByLanguage;
891085
- let languagesWithExistingSdkDynamicIr = /* @__PURE__ */ new Set();
891086
- if (Object.keys(snippetsConfig).length === 0) {
891087
- context3.logger.debug(`No snippets configuration defined, skipping snippet generation...`);
891088
- } else if (!disableDynamicSnippets) {
891089
- const existingSdkDynamicIrs = await checkAndDownloadExistingSdkDynamicIRs({
891090
- fdr,
891091
- workspace,
891092
- organization,
891093
- context: context3,
891094
- snippetsConfig
891095
- });
891096
- if (existingSdkDynamicIrs && Object.keys(existingSdkDynamicIrs).length > 0) {
891097
- dynamicIRsByLanguage = existingSdkDynamicIrs;
891098
- languagesWithExistingSdkDynamicIr = new Set(Object.keys(existingSdkDynamicIrs));
891099
- context3.logger.debug(`Using existing SDK dynamic IRs for: ${Object.keys(existingSdkDynamicIrs).join(", ")}`);
891100
- }
891101
- const generatedDynamicIRs = await generateLanguageSpecificDynamicIRs({
891102
- workspace,
891103
- organization,
891104
- context: context3,
891105
- snippetsConfig,
891106
- skipLanguages: languagesWithExistingSdkDynamicIr
891107
- });
891108
- if (generatedDynamicIRs) {
891109
- dynamicIRsByLanguage = {
891110
- ...dynamicIRsByLanguage,
891111
- ...generatedDynamicIRs
891112
- };
891113
- }
891114
- }
891115
- let response;
891116
- try {
891117
- response = await fdr.api.register.registerApiDefinition({
891118
- orgId: FdrAPI_exports.OrgId(organization),
891119
- apiId: FdrAPI_exports.ApiId(apiName ?? getOriginalName(ir11.apiName)),
891120
- definition: apiDefinition,
891121
- dynamicIRs: dynamicIRsByLanguage
891122
- });
891123
- } catch (error50) {
891124
- const errorDetails = extractErrorDetails(error50);
891125
- context3.logger.error(`FDR registerApiDefinition failed. Error details:
891126
- ${JSON.stringify(errorDetails, void 0, 2)}`);
891127
- if (apiName != null) {
891128
- return context3.failAndThrow(`Failed to publish docs because API definition (${apiName}) could not be uploaded. Please contact support@buildwithfern.com`, errorDetails, { code: CliError.Code.NetworkError });
891129
- } else {
891130
- return context3.failAndThrow(`Failed to publish docs because API definition could not be uploaded. Please contact support@buildwithfern.com`, errorDetails, { code: CliError.Code.NetworkError });
891131
- }
891132
- }
891133
- context3.logger.debug(`Registered API Definition ${apiName}: ${response.apiDefinitionId}`);
891134
- if (response.dynamicIRs && dynamicIRsByLanguage) {
891135
- if (skipUpload) {
891136
- context3.logger.debug("Skip-upload mode: skipping dynamic IR uploads");
891137
- } else {
891138
- await uploadDynamicIRs({
891139
- dynamicIRs: dynamicIRsByLanguage,
891140
- dynamicIRUploadUrls: response.dynamicIRs,
891141
- context: context3,
891142
- apiId: response.apiDefinitionId
891143
- });
891144
- }
891145
- }
891146
- return response.apiDefinitionId;
891147
- },
891468
+ registerApi: registerApiToFdr,
891469
+ buildTranslatedApiDefinitions,
891148
891470
  targetAudiences
891149
891471
  });
891150
891472
  context3.logger.info("Resolving docs definition...");
@@ -891184,6 +891506,27 @@ ${JSON.stringify(errorDetails, void 0, 2)}`);
891184
891506
  }
891185
891507
  const publishTime = performance.now() - publishStart;
891186
891508
  context3.logger.debug(`Docs published to FDR in ${publishTime.toFixed(0)}ms`);
891509
+ const translatedApiSpecsByLocale = buildTranslatedApiDefinitions ? resolver2.getTranslatedApiSpecs() : /* @__PURE__ */ new Map();
891510
+ const translatedApiIdsByLocale = /* @__PURE__ */ new Map();
891511
+ if (translatedApiSpecsByLocale.size > 0) {
891512
+ context3.logger.info(`Registering translated API definitions for ${translatedApiSpecsByLocale.size} locale(s)...`);
891513
+ for (const [locale, specsByBaseApiId] of translatedApiSpecsByLocale) {
891514
+ const idMap = /* @__PURE__ */ new Map();
891515
+ for (const [baseApiId, spec] of specsByBaseApiId) {
891516
+ try {
891517
+ const translatedApiId = await registerApiToFdr(spec);
891518
+ if (translatedApiId !== baseApiId) {
891519
+ idMap.set(baseApiId, translatedApiId);
891520
+ }
891521
+ } catch (error50) {
891522
+ context3.logger.warn(`Failed to register translated API definition for locale "${locale}" (API reference will render in the default language): ${String(error50)}`);
891523
+ }
891524
+ }
891525
+ if (idMap.size > 0) {
891526
+ translatedApiIdsByLocale.set(locale, idMap);
891527
+ }
891528
+ }
891529
+ }
891187
891530
  const translationPages = resolver2.getTranslationPages();
891188
891531
  const translationNavigationOverlays = resolver2.getTranslationNavigationOverlays();
891189
891532
  const translationDomain = preview ? urlToOutput : domain3;
@@ -891283,6 +891626,25 @@ ${JSON.stringify(errorDetails, void 0, 2)}`);
891283
891626
  translatedNavbarLinks = localeNavOverlay.navbarLinks;
891284
891627
  }
891285
891628
  }
891629
+ const localeApiIdMap = translatedApiIdsByLocale.get(locale);
891630
+ if (localeApiIdMap != null && localeApiIdMap.size > 0 && updatedRoot != null) {
891631
+ const baseApisForTitles = {};
891632
+ const translatedApisForTitles = {};
891633
+ for (const [baseApiId, translatedApiId] of localeApiIdMap) {
891634
+ const baseRead = readApiDefinitionsById.get(baseApiId);
891635
+ const translatedRead = readApiDefinitionsById.get(translatedApiId);
891636
+ if (baseRead != null) {
891637
+ baseApisForTitles[baseApiId] = baseRead;
891638
+ }
891639
+ if (translatedRead != null) {
891640
+ translatedApisForTitles[baseApiId] = translatedRead;
891641
+ }
891642
+ }
891643
+ updatedRoot = Object.keys(translatedApisForTitles).length > 0 ? applyTranslatedApiTitlesToNavTree(updatedRoot, baseApisForTitles, translatedApisForTitles) : structuredClone(updatedRoot);
891644
+ for (const [baseApiId, translatedApiId] of localeApiIdMap) {
891645
+ updateApiDefinitionIdInTree(updatedRoot, baseApiId, translatedApiId);
891646
+ }
891647
+ }
891286
891648
  const translatedDefinition = {
891287
891649
  ...docsDefinition,
891288
891650
  pages: translatedPages,
@@ -892013,7 +892375,7 @@ var LegacyDocsPublisher = class {
892013
892375
  previewId,
892014
892376
  disableTemplates: void 0,
892015
892377
  skipUpload,
892016
- cliVersion: "5.23.3-378-g4009024e80d",
892378
+ cliVersion: "5.23.3-382-g24ea8784553",
892017
892379
  loginCommand: "fern auth login"
892018
892380
  });
892019
892381
  if (taskContext.getResult() === TaskResult.Failure) {
@@ -895618,7 +895980,7 @@ var CONTAINER_SOURCES_DIRECTORY = DOCKER_SOURCES_DIRECTORY;
895618
895980
  var DOCKER_SPECS_DIRECTORY = import_path84.default.join(DOCKER_FERN_DIRECTORY, SPECS_DIRECTORY_NAME);
895619
895981
  var CONTAINER_SPECS_DIRECTORY = DOCKER_SPECS_DIRECTORY;
895620
895982
  var DEFAULT_NODE_DEBUG_PORT = "9229";
895621
- var GENERATORS_WANTING_SPECS = /* @__PURE__ */ new Set(["fernapi/fern-cli-generator"]);
895983
+ var GENERATORS_WANTING_SPECS = /* @__PURE__ */ new Set(["fernapi/fern-cli"]);
895622
895984
  function generatorWantsSpecs(generatorName) {
895623
895985
  return GENERATORS_WANTING_SPECS.has(generatorName);
895624
895986
  }
@@ -957100,7 +957462,7 @@ function getAutomationContextFromEnv() {
957100
957462
  config_branch: process.env.FERN_CONFIG_BRANCH,
957101
957463
  config_pr_number: process.env.FERN_CONFIG_PR_NUMBER,
957102
957464
  trigger: process.env.GITHUB_EVENT_NAME,
957103
- cli_version: "5.23.3-378-g4009024e80d"
957465
+ cli_version: "5.23.3-382-g24ea8784553"
957104
957466
  };
957105
957467
  }
957106
957468
  function isAutomationMode() {
@@ -957926,7 +958288,7 @@ var CliContext = class _CliContext {
957926
958288
  if (false) {
957927
958289
  this.logger.error("CLI_VERSION is not defined");
957928
958290
  }
957929
- return "5.23.3-378-g4009024e80d";
958291
+ return "5.23.3-382-g24ea8784553";
957930
958292
  }
957931
958293
  getCliName() {
957932
958294
  if (false) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.23.3-378-g4009024e80d",
2
+ "version": "5.23.3-382-g24ea8784553",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",