@fern-api/fern-api-dev 5.65.4 → 5.65.6

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 +381 -166
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -89377,6 +89377,26 @@ var init_ClonedRepository = __esm({
89377
89377
  const result = await this.git.raw(["rev-parse", `${commitSha}^{tree}`]);
89378
89378
  return result.trim();
89379
89379
  }
89380
+ async getCommitMessage(commitSha) {
89381
+ await this.git.cwd(this.clonePath);
89382
+ const result = await this.git.raw(["log", "-1", "--format=%B", commitSha]);
89383
+ return result.replace(/\n$/, "");
89384
+ }
89385
+ async getCommitParents(commitSha) {
89386
+ await this.git.cwd(this.clonePath);
89387
+ const result = await this.git.raw(["rev-list", "--parents", "-n", "1", commitSha]);
89388
+ const parts = result.trim().split(/\s+/);
89389
+ return parts.slice(1);
89390
+ }
89391
+ /**
89392
+ * Returns the SHAs of commits reachable from HEAD but not from any remote-tracking ref,
89393
+ * ordered oldest-first. These are the commits created locally that have not been pushed.
89394
+ */
89395
+ async getLocalOnlyCommits() {
89396
+ await this.git.cwd(this.clonePath);
89397
+ const result = await this.git.raw(["rev-list", "--reverse", "HEAD", "--not", "--remotes=origin"]);
89398
+ return result.trim().split("\n").filter((line) => line.length > 0);
89399
+ }
89380
89400
  /**
89381
89401
  * Returns true if the working tree has uncommitted changes (staged or unstaged).
89382
89402
  */
@@ -450038,6 +450058,13 @@ function parseImagePaths(markdown, metadata, context3) {
450038
450058
  }
450039
450059
  visitFrontmatterImages(data2, ["image", "og:image", "og:logo", "twitter:image"], mapImage);
450040
450060
  replaceFrontmatterImagesforLogo(data2, mapImage);
450061
+ const hasImageIndicators = content5.includes("![") || content5.includes("src=") || content5.includes("icon=");
450062
+ if (!hasImageIndicators) {
450063
+ return {
450064
+ filepaths: [...filepaths],
450065
+ markdown: requoteLeadingZeroValues(import_gray_matter3.default.stringify(content5, data2))
450066
+ };
450067
+ }
450041
450068
  const contentBytes = Buffer.byteLength(content5, "utf8");
450042
450069
  const isLargeFile = contentBytes > getLargeFileBytes();
450043
450070
  let replacedContent;
@@ -450237,142 +450264,208 @@ function replaceImagePathsAndUrls(markdown, fileIdsMap, markdownFilesToPathName,
450237
450264
  }
450238
450265
  visitFrontmatterImages(data2, ["image", "og:image", "og:logo", "twitter:image"], mapImage);
450239
450266
  replaceFrontmatterImagesforLogo(data2, mapImage);
450240
- const contentBytes = Buffer.byteLength(content5, "utf8");
450241
- const isLargeFile = contentBytes > getLargeFileBytes();
450242
- let replacedContent;
450243
- if (isLargeFile) {
450244
- context3.logger.debug(`Using streaming parser for large file replacement: ${metadata.absolutePathToMarkdownFile} (${(contentBytes / 1024 / 1024).toFixed(2)} MB)`);
450245
- const streamingStart = performance.now();
450246
- const edits = [];
450247
- let i5 = 0;
450248
- const len = content5.length;
450249
- while (i5 < len) {
450250
- if (content5[i5] === "!" && content5[i5 + 1] === "[") {
450251
- const result = parseMarkdownImage(content5, i5, metadata);
450252
- if (result) {
450253
- const imageSrc = mapImage(result.src);
450254
- if (imageSrc) {
450255
- edits.push({
450256
- start: result.edit.start,
450257
- end: result.edit.end,
450258
- replacement: result.originalUrl.replace(result.rawSrc, imageSrc)
450259
- });
450260
- }
450261
- i5 = result.nextIndex;
450262
- continue;
450267
+ const edits = [];
450268
+ let hasUnhandledExpressions = false;
450269
+ let i5 = 0;
450270
+ const len = content5.length;
450271
+ while (i5 < len) {
450272
+ if (content5[i5] === "!" && content5[i5 + 1] === "[") {
450273
+ const result = parseMarkdownImage(content5, i5, metadata);
450274
+ if (result) {
450275
+ const imageSrc = mapImage(result.src);
450276
+ if (imageSrc) {
450277
+ edits.push({
450278
+ start: result.edit.start,
450279
+ end: result.edit.end,
450280
+ replacement: result.originalUrl.replace(result.rawSrc, imageSrc)
450281
+ });
450263
450282
  }
450264
- } else if (content5[i5] === "[" && content5[i5 - 1] !== "!") {
450265
- const linkStart = i5;
450266
- let j5 = i5 + 1;
450267
- while (j5 < len && content5[j5] !== "]") {
450283
+ i5 = result.nextIndex;
450284
+ continue;
450285
+ }
450286
+ } else if (content5[i5] === "[" && content5[i5 - 1] !== "!") {
450287
+ let j5 = i5 + 1;
450288
+ while (j5 < len && content5[j5] !== "]") {
450289
+ if (content5[j5] === "\\") {
450290
+ j5 += 2;
450291
+ } else {
450292
+ j5++;
450293
+ }
450294
+ }
450295
+ if (j5 < len && content5[j5] === "]" && content5[j5 + 1] === "(") {
450296
+ j5 += 2;
450297
+ const urlStart = j5;
450298
+ let parenDepth = 1;
450299
+ while (j5 < len && parenDepth > 0) {
450268
450300
  if (content5[j5] === "\\") {
450269
450301
  j5 += 2;
450302
+ } else if (content5[j5] === "(") {
450303
+ parenDepth++;
450304
+ j5++;
450305
+ } else if (content5[j5] === ")") {
450306
+ parenDepth--;
450307
+ j5++;
450270
450308
  } else {
450271
450309
  j5++;
450272
450310
  }
450273
450311
  }
450274
- if (j5 < len && content5[j5] === "]" && content5[j5 + 1] === "(") {
450275
- j5 += 2;
450276
- const urlStart = j5;
450277
- let parenDepth = 1;
450278
- while (j5 < len && parenDepth > 0) {
450279
- if (content5[j5] === "\\") {
450280
- j5 += 2;
450281
- } else if (content5[j5] === "(") {
450282
- parenDepth++;
450283
- j5++;
450284
- } else if (content5[j5] === ")") {
450285
- parenDepth--;
450286
- j5++;
450287
- } else {
450312
+ const urlEnd = j5 - 1;
450313
+ const href = content5.slice(urlStart, urlEnd).trim();
450314
+ const trimmedHref = trimAnchor(href) ?? href;
450315
+ const hrefAnchor = trimmedHref !== href ? href.slice(trimmedHref.length) : "";
450316
+ const replacedHref = getReplacedHref({
450317
+ href: trimmedHref,
450318
+ markdownFilesToPathName,
450319
+ metadata
450320
+ });
450321
+ if (replacedHref && replacedHref.type === "replace") {
450322
+ edits.push({
450323
+ start: urlStart,
450324
+ end: urlEnd,
450325
+ replacement: replacedHref.slug + hrefAnchor
450326
+ });
450327
+ }
450328
+ i5 = j5;
450329
+ continue;
450330
+ }
450331
+ } else if (content5[i5] === "<") {
450332
+ let j5 = i5 + 1;
450333
+ while (j5 < len && content5[j5] !== ">" && content5[j5] !== " " && content5[j5] !== "\n") {
450334
+ j5++;
450335
+ }
450336
+ while (j5 < len && content5[j5] !== ">") {
450337
+ while (j5 < len && (content5[j5] === " " || content5[j5] === "\n")) {
450338
+ j5++;
450339
+ }
450340
+ const attrStart = j5;
450341
+ while (j5 < len && content5[j5] !== "=" && content5[j5] !== ">" && content5[j5] !== " " && content5[j5] !== "\n") {
450342
+ j5++;
450343
+ }
450344
+ const attrName = content5.slice(attrStart, j5).trim();
450345
+ if (attrName.startsWith("{")) {
450346
+ hasUnhandledExpressions = true;
450347
+ let braceDepth = 0;
450348
+ j5 = attrStart;
450349
+ while (j5 < len) {
450350
+ if (content5[j5] === "{") {
450351
+ braceDepth++;
450352
+ } else if (content5[j5] === "}") {
450353
+ braceDepth--;
450354
+ if (braceDepth === 0) {
450355
+ j5++;
450356
+ break;
450357
+ }
450358
+ } else if (content5[j5] === '"' || content5[j5] === "'") {
450359
+ const q5 = content5[j5];
450288
450360
  j5++;
450361
+ while (j5 < len && content5[j5] !== q5) {
450362
+ if (content5[j5] === "\\") {
450363
+ j5++;
450364
+ }
450365
+ j5++;
450366
+ }
450289
450367
  }
450368
+ j5++;
450290
450369
  }
450291
- const urlEnd = j5 - 1;
450292
- const href = content5.slice(urlStart, urlEnd).trim();
450293
- const replacedHref = getReplacedHref({ href, markdownFilesToPathName, metadata });
450294
- if (replacedHref && replacedHref.type === "replace") {
450295
- edits.push({ start: urlStart, end: urlEnd, replacement: replacedHref.slug });
450296
- }
450297
- i5 = j5;
450298
450370
  continue;
450299
450371
  }
450300
- } else if (content5[i5] === "<") {
450301
- let j5 = i5 + 1;
450302
- while (j5 < len && content5[j5] !== ">" && content5[j5] !== " " && content5[j5] !== "\n") {
450372
+ if (content5[j5] === "=") {
450303
450373
  j5++;
450304
- }
450305
- while (j5 < len && content5[j5] !== ">") {
450306
450374
  while (j5 < len && (content5[j5] === " " || content5[j5] === "\n")) {
450307
450375
  j5++;
450308
450376
  }
450309
- const attrStart = j5;
450310
- while (j5 < len && content5[j5] !== "=" && content5[j5] !== ">" && content5[j5] !== " " && content5[j5] !== "\n") {
450311
- j5++;
450312
- }
450313
- const attrName = content5.slice(attrStart, j5).trim();
450314
- if (content5[j5] === "=") {
450377
+ const isCurlyWrapped = content5[j5] === "{";
450378
+ if (isCurlyWrapped) {
450315
450379
  j5++;
450316
450380
  while (j5 < len && (content5[j5] === " " || content5[j5] === "\n")) {
450317
450381
  j5++;
450318
450382
  }
450319
- if (content5[j5] === '"' || content5[j5] === "'") {
450320
- const quote2 = content5[j5];
450321
- j5++;
450322
- const valueStart = j5;
450323
- while (j5 < len && content5[j5] !== quote2) {
450324
- if (content5[j5] === "\\") {
450325
- j5 += 2;
450326
- } else {
450327
- j5++;
450328
- }
450383
+ }
450384
+ if (content5[j5] === '"' || content5[j5] === "'") {
450385
+ const quote2 = content5[j5];
450386
+ j5++;
450387
+ const valueStart = j5;
450388
+ while (j5 < len && content5[j5] !== quote2) {
450389
+ if (content5[j5] === "\\") {
450390
+ j5 += 2;
450391
+ } else {
450392
+ j5++;
450329
450393
  }
450330
- const value2 = content5.slice(valueStart, j5);
450331
- j5++;
450332
- if (attrName === "src" || attrName === "icon" && isLocalIconReference(value2)) {
450333
- const imageSrc = mapImage(value2);
450334
- if (imageSrc) {
450335
- edits.push({
450336
- start: valueStart,
450337
- end: valueStart + value2.length,
450338
- replacement: imageSrc
450339
- });
450340
- }
450341
- } else if (attrName === "href") {
450342
- const replacedHref = getReplacedHref({
450343
- href: value2,
450344
- markdownFilesToPathName,
450345
- metadata
450394
+ }
450395
+ const value2 = content5.slice(valueStart, j5);
450396
+ j5++;
450397
+ if (isCurlyWrapped) {
450398
+ while (j5 < len && (content5[j5] === " " || content5[j5] === "\n")) {
450399
+ j5++;
450400
+ }
450401
+ if (j5 < len && content5[j5] === "}") {
450402
+ j5++;
450403
+ }
450404
+ }
450405
+ if (attrName === "src" || attrName === "icon" && isLocalIconReference(value2)) {
450406
+ const trimmedValue = trimAnchor(value2);
450407
+ const anchor = trimmedValue && value2 !== trimmedValue ? value2.slice(trimmedValue.length) : "";
450408
+ const imageSrc = mapImage(trimmedValue ?? value2);
450409
+ if (imageSrc) {
450410
+ edits.push({
450411
+ start: valueStart,
450412
+ end: valueStart + value2.length,
450413
+ replacement: imageSrc + anchor
450346
450414
  });
450347
- if (replacedHref && replacedHref.type === "replace") {
450348
- edits.push({
450349
- start: valueStart,
450350
- end: valueStart + value2.length,
450351
- replacement: replacedHref.slug
450352
- });
450415
+ }
450416
+ } else if (attrName === "href") {
450417
+ const trimmedHrefValue = trimAnchor(value2) ?? value2;
450418
+ const hrefAnchorSuffix = trimmedHrefValue !== value2 ? value2.slice(trimmedHrefValue.length) : "";
450419
+ const replacedHref = getReplacedHref({
450420
+ href: trimmedHrefValue,
450421
+ markdownFilesToPathName,
450422
+ metadata
450423
+ });
450424
+ if (replacedHref && replacedHref.type === "replace") {
450425
+ edits.push({
450426
+ start: valueStart,
450427
+ end: valueStart + value2.length,
450428
+ replacement: replacedHref.slug + hrefAnchorSuffix
450429
+ });
450430
+ }
450431
+ }
450432
+ } else if (isCurlyWrapped && (attrName === "src" || attrName === "icon" || attrName === "href")) {
450433
+ hasUnhandledExpressions = true;
450434
+ let braceDepth = 1;
450435
+ while (j5 < len && braceDepth > 0) {
450436
+ if (content5[j5] === "{") {
450437
+ braceDepth++;
450438
+ } else if (content5[j5] === "}") {
450439
+ braceDepth--;
450440
+ } else if (content5[j5] === '"' || content5[j5] === "'") {
450441
+ const q5 = content5[j5];
450442
+ j5++;
450443
+ while (j5 < len && content5[j5] !== q5) {
450444
+ if (content5[j5] === "\\") {
450445
+ j5++;
450446
+ }
450447
+ j5++;
450353
450448
  }
450354
450449
  }
450450
+ j5++;
450355
450451
  }
450356
450452
  }
450357
450453
  }
450358
- if (j5 < len && content5[j5] === ">") {
450359
- j5++;
450360
- }
450361
- i5 = j5;
450362
- continue;
450363
450454
  }
450364
- i5++;
450455
+ if (j5 < len && content5[j5] === ">") {
450456
+ j5++;
450457
+ }
450458
+ i5 = j5;
450459
+ continue;
450365
450460
  }
450366
- replacedContent = applyEdits(content5, edits);
450367
- const streamingTime = performance.now() - streamingStart;
450368
- context3.logger.debug(`Streaming replacement completed in ${streamingTime.toFixed(0)}ms: ${edits.length} edits applied`);
450369
- } else {
450461
+ i5++;
450462
+ }
450463
+ if (hasUnhandledExpressions) {
450370
450464
  const tree = parseMarkdownToTree(content5);
450371
450465
  const lineStarts = precomputeLineStarts(content5);
450372
- const edits = [];
450373
450466
  const nodeTypeFilter = (node4) => {
450374
450467
  const n2 = node4;
450375
- return n2.type === "image" || n2.type === "link" || n2.type === "mdxJsxFlowElement" || n2.type === "mdxJsxTextElement" || n2.type === "mdxFlowExpression" || n2.type === "mdxTextExpression";
450468
+ return n2.type === "mdxJsxFlowElement" || n2.type === "mdxJsxTextElement" || n2.type === "mdxFlowExpression" || n2.type === "mdxTextExpression";
450376
450469
  };
450377
450470
  visit3(tree, nodeTypeFilter, (node4) => {
450378
450471
  if (node4.position == null) {
@@ -450405,25 +450498,12 @@ function replaceImagePathsAndUrls(markdown, fileIdsMap, markdownFilesToPathName,
450405
450498
  href: (attr) => replaceHref(trimAnchor(extractSingleLiteral(attr.value)))
450406
450499
  });
450407
450500
  }
450408
- if (node4.type === "image") {
450409
- const src = trimAnchor(node4.url);
450410
- replaceSrc(trimAnchor(src));
450411
- }
450412
- if (node4.type === "link") {
450413
- replaceHref(trimAnchor(node4.url));
450414
- }
450415
450501
  if (isMdxJsxElement(node4)) {
450416
- const srcAttr = node4.attributes.filter(isMdxJsxAttribute).find((attr) => attr.name === "src");
450417
- replaceSrc(trimAnchor(extractAttributeValueLiteral(srcAttr?.value)));
450418
- const iconAttr = node4.attributes.filter(isMdxJsxAttribute).find((attr) => attr.name === "icon");
450419
- const iconValue = trimAnchor(extractAttributeValueLiteral(iconAttr?.value));
450420
- if (isLocalIconReference(iconValue)) {
450421
- replaceSrc(iconValue);
450422
- }
450423
- const hrefAttr = node4.attributes.find((attr) => attr.type === "mdxJsxAttribute" && attr.name === "href");
450424
- replaceHref(trimAnchor(extractAttributeValueLiteral(hrefAttr?.value)));
450425
450502
  node4.attributes.forEach((attr) => {
450426
450503
  if (isMdxJsxAttribute(attr) && typeof attr.value !== "string" && attr.value != null && attr.value.data?.estree) {
450504
+ if (extractSingleLiteral(attr.value.data.estree) != null) {
450505
+ return;
450506
+ }
450427
450507
  walkEstreeForSrcAndHref(attr.value.data.estree);
450428
450508
  } else if (isMdxJsxExpressionAttribute(attr) && attr.data?.estree) {
450429
450509
  walkEstreeForSrcAndHref(attr.data.estree);
@@ -450438,8 +450518,8 @@ function replaceImagePathsAndUrls(markdown, fileIdsMap, markdownFilesToPathName,
450438
450518
  }
450439
450519
  return CONTINUE;
450440
450520
  });
450441
- replacedContent = applyEdits(content5, edits);
450442
450521
  }
450522
+ const replacedContent = applyEdits(content5, edits);
450443
450523
  return requoteLeadingZeroValues(import_gray_matter3.default.stringify(replacedContent, data2));
450444
450524
  }
450445
450525
  function trimAnchor(text9) {
@@ -450570,18 +450650,56 @@ function extractLines(content5, linesParam) {
450570
450650
  const extractedLines = sortedIndices.filter((idx) => idx >= 0 && idx < allLines.length).map((idx) => allLines[idx] ?? "");
450571
450651
  return extractedLines.join("\n");
450572
450652
  }
450653
+ function collectCodeSrcUrls(markdown) {
450654
+ if (!markdown.includes("<Code")) {
450655
+ return [];
450656
+ }
450657
+ const urls = [];
450658
+ const regex6 = new RegExp(CODE_TAG_REGEX.source, CODE_TAG_REGEX.flags);
450659
+ let match3;
450660
+ while ((match3 = regex6.exec(markdown)) != null) {
450661
+ const src = match3[2];
450662
+ if (src && isUrl(src)) {
450663
+ urls.push(src);
450664
+ }
450665
+ }
450666
+ return urls;
450667
+ }
450668
+ async function prefetchCodeSrcUrls(urls, context3) {
450669
+ const cache2 = /* @__PURE__ */ new Map();
450670
+ const unique = [...new Set(urls)];
450671
+ if (unique.length === 0) {
450672
+ return cache2;
450673
+ }
450674
+ const results = await Promise.allSettled(unique.map(async (url3) => {
450675
+ const response = await fetch(url3);
450676
+ if (!response.ok) {
450677
+ context3.logger.warn(`Failed to prefetch code from URL "${url3}" (status ${response.status})`);
450678
+ return { url: url3, content: void 0 };
450679
+ }
450680
+ const content5 = await response.text();
450681
+ return { url: url3, content: content5 };
450682
+ }));
450683
+ for (const result of results) {
450684
+ if (result.status === "fulfilled" && result.value.content !== void 0) {
450685
+ cache2.set(result.value.url, result.value.content);
450686
+ }
450687
+ }
450688
+ return cache2;
450689
+ }
450573
450690
  async function replaceReferencedCode({
450574
450691
  markdown,
450575
450692
  absolutePathToFernFolder,
450576
450693
  absolutePathToMarkdownFile,
450577
450694
  context: context3,
450578
450695
  // allow for custom markdown loader for testing
450579
- fileLoader = defaultFileLoader
450696
+ fileLoader = defaultFileLoader,
450697
+ urlCache
450580
450698
  }) {
450581
450699
  if (!markdown.includes("<Code")) {
450582
450700
  return markdown;
450583
450701
  }
450584
- const regex6 = /([ \t]*)<Code(?:\s+[^>]*?)?\s+src={?['"]([^'"]+)['"](?! \+)}?((?:\s+[^>]*)?)\/>/g;
450702
+ const regex6 = new RegExp(CODE_TAG_REGEX.source, CODE_TAG_REGEX.flags);
450585
450703
  let newMarkdown = markdown;
450586
450704
  let match3;
450587
450705
  while ((match3 = regex6.exec(markdown)) != null) {
@@ -450596,21 +450714,26 @@ async function replaceReferencedCode({
450596
450714
  let language;
450597
450715
  let title2;
450598
450716
  if (isUrl(src)) {
450599
- try {
450600
- const response = await fetch(src);
450601
- if (!response.ok) {
450602
- context3.logger.warn(`Failed to fetch code from URL "${src}" (status ${response.status}) referenced in ${absolutePathToMarkdownFile}`);
450717
+ const cached2 = urlCache?.get(src);
450718
+ if (cached2 !== void 0) {
450719
+ replacement = cached2;
450720
+ } else {
450721
+ try {
450722
+ const response = await fetch(src);
450723
+ if (!response.ok) {
450724
+ context3.logger.warn(`Failed to fetch code from URL "${src}" (status ${response.status}) referenced in ${absolutePathToMarkdownFile}`);
450725
+ break;
450726
+ }
450727
+ replacement = await response.text();
450728
+ } catch (e2) {
450729
+ context3.logger.warn(`Failed to fetch code from URL "${src}" referenced in ${absolutePathToMarkdownFile}: ${e2}`);
450603
450730
  break;
450604
450731
  }
450605
- replacement = await response.text();
450606
- const url3 = new URL(src);
450607
- const pathname = url3.pathname;
450608
- language = pathname.split(".").pop();
450609
- title2 = pathname.split("/").pop();
450610
- } catch (e2) {
450611
- context3.logger.warn(`Failed to fetch code from URL "${src}" referenced in ${absolutePathToMarkdownFile}: ${e2}`);
450612
- break;
450613
450732
  }
450733
+ const url3 = new URL(src);
450734
+ const pathname = url3.pathname;
450735
+ language = pathname.split(".").pop();
450736
+ title2 = pathname.split("/").pop();
450614
450737
  } else {
450615
450738
  const filepath = resolve6(src.startsWith("/") ? absolutePathToFernFolder : dirname6(absolutePathToMarkdownFile), RelativeFilePath2.of(src.replace(/^\//, "")));
450616
450739
  replacement = await fileLoader(filepath);
@@ -450693,12 +450816,13 @@ ${replacement}
450693
450816
  }
450694
450817
  return newMarkdown;
450695
450818
  }
450696
- var import_promises68;
450819
+ var import_promises68, CODE_TAG_REGEX;
450697
450820
  var init_replaceReferencedCode = __esm({
450698
450821
  "../docs-markdown-utils/lib/replaceReferencedCode.js"() {
450699
450822
  "use strict";
450700
450823
  init_lib8();
450701
450824
  import_promises68 = require("fs/promises");
450825
+ CODE_TAG_REGEX = /([ \t]*)<Code(?:\s+[^>]*?)?\s+src={?['"]([^'"]+)['"](?! \+)}?((?:\s+[^>]*)?)\/>/g;
450702
450826
  }
450703
450827
  });
450704
450828
 
@@ -450916,6 +451040,7 @@ var init_transformAtPrefixImports = __esm({
450916
451040
  // ../docs-markdown-utils/lib/index.js
450917
451041
  var lib_exports10 = {};
450918
451042
  __export(lib_exports10, {
451043
+ collectCodeSrcUrls: () => collectCodeSrcUrls,
450919
451044
  extractAttributeValueLiteral: () => extractAttributeValueLiteral,
450920
451045
  extractSingleLiteral: () => extractSingleLiteral,
450921
451046
  getMarkdownFormat: () => getMarkdownFormat,
@@ -450927,6 +451052,7 @@ __export(lib_exports10, {
450927
451052
  isValidRelativeSlug: () => isValidRelativeSlug,
450928
451053
  parseImagePaths: () => parseImagePaths,
450929
451054
  parseMarkdownToTree: () => parseMarkdownToTree,
451055
+ prefetchCodeSrcUrls: () => prefetchCodeSrcUrls,
450930
451056
  replaceImagePathsAndUrls: () => replaceImagePathsAndUrls,
450931
451057
  replaceReferencedCode: () => replaceReferencedCode,
450932
451058
  replaceReferencedMarkdown: () => replaceReferencedMarkdown,
@@ -460601,7 +460727,18 @@ var init_DocsDefinitionResolver = __esm({
460601
460727
  this.taskContext.logger.debug("Replacing referenced markdown and code files...");
460602
460728
  const refStart = performance.now();
460603
460729
  const seenReferencedFiles = /* @__PURE__ */ new Set();
460604
- for (const [relativePath, markdown] of Object.entries(this.parsedDocsConfig.pages)) {
460730
+ const pageEntries = Object.entries(this.parsedDocsConfig.pages);
460731
+ const allCodeSrcUrls = [];
460732
+ for (const [, markdown] of pageEntries) {
460733
+ allCodeSrcUrls.push(...collectCodeSrcUrls(markdown));
460734
+ }
460735
+ const prefetchStart = Date.now();
460736
+ const urlCache = await prefetchCodeSrcUrls(allCodeSrcUrls, this.taskContext);
460737
+ if (urlCache.size > 0) {
460738
+ const uniqueCount = new Set(allCodeSrcUrls).size;
460739
+ this.taskContext.logger.info(`Prefetched ${uniqueCount} external code URLs in ${Date.now() - prefetchStart}ms`);
460740
+ }
460741
+ for (const [relativePath, markdown] of pageEntries) {
460605
460742
  const result = await replaceReferencedMarkdown({
460606
460743
  markdown,
460607
460744
  absolutePathToFernFolder: this.docsWorkspace.absoluteFilePath,
@@ -460618,7 +460755,8 @@ var init_DocsDefinitionResolver = __esm({
460618
460755
  markdown: result.markdown,
460619
460756
  absolutePathToFernFolder: this.docsWorkspace.absoluteFilePath,
460620
460757
  absolutePathToMarkdownFile: this.resolveFilepath(relativePath),
460621
- context: this.taskContext
460758
+ context: this.taskContext,
460759
+ urlCache
460622
460760
  });
460623
460761
  const newMarkdown = transformAtPrefixImports({
460624
460762
  markdown: codeReplacedMarkdown,
@@ -581321,29 +581459,24 @@ var require_pushSignedCommit = __commonJS({
581321
581459
  exports2.isNonFastForwardError = isNonFastForwardError;
581322
581460
  var core_utils_1 = (init_lib4(), __toCommonJS(lib_exports));
581323
581461
  var MAX_CONCURRENT_PUSH_RETRIES = 3;
581462
+ var MAX_SIGNED_CHAIN_LENGTH = 20;
581324
581463
  async function pushSignedCommit({ repository, octokit, owner, repo, branch, force, rebaseOnConflict = false, author, logger: logger4 }) {
581325
581464
  const tempRef = `refs/temp/fern-${Date.now()}`;
581326
581465
  let tempRefPushed = false;
581327
581466
  try {
581328
- let [localHeadSha, treeSha, message, parents] = await Promise.all([
581329
- repository.getHeadSha(),
581330
- repository.getHeadTreeHash(),
581331
- repository.getHeadCommitMessage(),
581332
- repository.getHeadParents()
581333
- ]);
581467
+ let localHeadSha = await repository.getHeadSha();
581334
581468
  await repository.pushObjectToRef(localHeadSha, tempRef);
581335
581469
  tempRefPushed = true;
581336
581470
  for (let attempt = 0; attempt < MAX_CONCURRENT_PUSH_RETRIES; attempt++) {
581337
- const identityFields = author != null ? { author, committer: author } : {};
581338
- const { data: signedCommit } = await octokit.git.createCommit({
581471
+ const signedSha = await signLocalCommitChain({
581472
+ repository,
581473
+ octokit,
581339
581474
  owner,
581340
581475
  repo,
581341
- message,
581342
- tree: treeSha,
581343
- parents,
581344
- ...identityFields
581476
+ localHeadSha,
581477
+ author,
581478
+ logger: logger4
581345
581479
  });
581346
- const signedSha = signedCommit.sha;
581347
581480
  try {
581348
581481
  await upsertBranchRef({ octokit, owner, repo, branch, sha: signedSha, force });
581349
581482
  logger4.debug(`Updated refs/heads/${branch} to signed commit ${signedSha}`);
@@ -581356,12 +581489,7 @@ var require_pushSignedCommit = __commonJS({
581356
581489
  if (rebaseOnConflict) {
581357
581490
  logger4.warn(`Non-fast-forward on refs/heads/${branch} (attempt ${attempt + 1}/${MAX_CONCURRENT_PUSH_RETRIES}); rebasing locally and retrying.`);
581358
581491
  await repository.pullWithRebase(branch);
581359
- [localHeadSha, treeSha, message, parents] = await Promise.all([
581360
- repository.getHeadSha(),
581361
- repository.getHeadTreeHash(),
581362
- repository.getHeadCommitMessage(),
581363
- repository.getHeadParents()
581364
- ]);
581492
+ localHeadSha = await repository.getHeadSha();
581365
581493
  await repository.pushObjectToRef(localHeadSha, tempRef, { force: true });
581366
581494
  } else {
581367
581495
  throw err;
@@ -581379,6 +581507,39 @@ var require_pushSignedCommit = __commonJS({
581379
581507
  }
581380
581508
  }
581381
581509
  }
581510
+ async function signLocalCommitChain({ repository, octokit, owner, repo, localHeadSha, author, logger: logger4 }) {
581511
+ let chain = await repository.getLocalOnlyCommits();
581512
+ if (chain.length === 0 || chain[chain.length - 1] !== localHeadSha) {
581513
+ chain = [localHeadSha];
581514
+ } else if (chain.length > MAX_SIGNED_CHAIN_LENGTH) {
581515
+ logger4.warn(`Local commit chain has ${chain.length} commits (limit ${MAX_SIGNED_CHAIN_LENGTH}); signing HEAD only.`);
581516
+ chain = [localHeadSha];
581517
+ }
581518
+ const identityFields = author != null ? { author, committer: author } : {};
581519
+ const signedShaByLocalSha = /* @__PURE__ */ new Map();
581520
+ let signedSha = localHeadSha;
581521
+ for (const sha of chain) {
581522
+ const [treeSha, message, parents] = await Promise.all([
581523
+ repository.getCommitTreeHash(sha),
581524
+ repository.getCommitMessage(sha),
581525
+ repository.getCommitParents(sha)
581526
+ ]);
581527
+ const { data: signedCommit } = await octokit.git.createCommit({
581528
+ owner,
581529
+ repo,
581530
+ message,
581531
+ tree: treeSha,
581532
+ parents: parents.map((parent) => signedShaByLocalSha.get(parent) ?? parent),
581533
+ ...identityFields
581534
+ });
581535
+ signedShaByLocalSha.set(sha, signedCommit.sha);
581536
+ signedSha = signedCommit.sha;
581537
+ }
581538
+ if (chain.length > 1) {
581539
+ logger4.debug(`Signed ${chain.length} local commits via the GitHub API`);
581540
+ }
581541
+ return signedSha;
581542
+ }
581382
581543
  async function upsertBranchRef({ octokit, owner, repo, branch, sha, force }) {
581383
581544
  try {
581384
581545
  await octokit.git.updateRef({
@@ -582008,7 +582169,9 @@ var require_ReplayStep = __commonJS({
582008
582169
  "use strict";
582009
582170
  Object.defineProperty(exports2, "__esModule", { value: true });
582010
582171
  exports2.ReplayStep = void 0;
582172
+ var child_process_1 = require("child_process");
582011
582173
  var replay_run_1 = require_replay_run();
582174
+ var constants_1 = require_constants8();
582012
582175
  var BaseStep_1 = require_BaseStep();
582013
582176
  var ReplayStep = class extends BaseStep_1.BaseStep {
582014
582177
  config;
@@ -582050,17 +582213,21 @@ var require_ReplayStep = __commonJS({
582050
582213
  patchesWithConflicts: 0
582051
582214
  };
582052
582215
  }
582216
+ const stageOnly = this.config.stageOnly ?? false;
582053
582217
  const result = prepared != null ? await (0, replay_run_1.replayApply)(prepared, {
582054
- stageOnly: this.config.stageOnly ?? false,
582218
+ stageOnly,
582055
582219
  logger: this.logger
582056
582220
  }) : await (0, replay_run_1.replayRun)({
582057
582221
  outputDir: this.outputDir,
582058
582222
  cliVersion: this.cliVersion,
582059
582223
  generatorVersions: this.generatorVersions,
582060
- stageOnly: this.config.stageOnly ?? false,
582224
+ stageOnly,
582061
582225
  skipApplication: this.config.skipApplication,
582062
582226
  logger: this.logger
582063
582227
  });
582228
+ if (!stageOnly) {
582229
+ this.commitLockfileIfUncommitted();
582230
+ }
582064
582231
  if (result.failureReason != null) {
582065
582232
  return {
582066
582233
  executed: true,
@@ -582124,6 +582291,40 @@ var require_ReplayStep = __commonJS({
582124
582291
  warnings: report.warnings
582125
582292
  };
582126
582293
  }
582294
+ /**
582295
+ * Commits `.fern/replay.lock` when replay saved the lockfile to disk but
582296
+ * didn't create a `[fern-replay]` commit (e.g. no-patches flow with zero
582297
+ * new patches). Without this, `skipCommit = true` in GithubStep drops the
582298
+ * lockfile advance, freezing `previousGenerationSha` across runs.
582299
+ */
582300
+ commitLockfileIfUncommitted() {
582301
+ try {
582302
+ const status = (0, child_process_1.execFileSync)("git", ["status", "--porcelain", "--", ".fern/replay.lock"], {
582303
+ cwd: this.outputDir,
582304
+ encoding: "utf-8",
582305
+ stdio: ["pipe", "pipe", "pipe"]
582306
+ }).trim();
582307
+ if (status.length === 0) {
582308
+ return;
582309
+ }
582310
+ (0, child_process_1.execFileSync)("git", ["add", "--", ".fern/replay.lock"], {
582311
+ cwd: this.outputDir,
582312
+ stdio: "pipe"
582313
+ });
582314
+ (0, child_process_1.execFileSync)("git", [
582315
+ "-c",
582316
+ `user.name=${constants_1.FERN_BOT_NAME}`,
582317
+ "-c",
582318
+ `user.email=${constants_1.FERN_BOT_EMAIL}`,
582319
+ "commit",
582320
+ "-m",
582321
+ "[fern-replay] advance lockfile"
582322
+ ], { cwd: this.outputDir, stdio: "pipe" });
582323
+ this.logger.debug("ReplayStep: committed uncommitted lockfile advance.");
582324
+ } catch (error50) {
582325
+ this.logger.debug("ReplayStep: failed to commit lockfile advance: " + String(error50));
582326
+ }
582327
+ }
582127
582328
  };
582128
582329
  exports2.ReplayStep = ReplayStep;
582129
582330
  }
@@ -688438,7 +688639,7 @@ var AccessTokenPosthogManager = class {
688438
688639
  properties: {
688439
688640
  ...event,
688440
688641
  ...event.properties,
688441
- version: "5.65.4",
688642
+ version: "5.65.6",
688442
688643
  usingAccessToken: true,
688443
688644
  ...getRunIdProperties()
688444
688645
  }
@@ -688504,7 +688705,7 @@ var UserPosthogManager = class {
688504
688705
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
688505
688706
  event: "CLI",
688506
688707
  properties: {
688507
- version: "5.65.4",
688708
+ version: "5.65.6",
688508
688709
  ...event,
688509
688710
  ...event.properties,
688510
688711
  usingAccessToken: false,
@@ -869600,7 +869801,7 @@ var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
869600
869801
  var LOGS_FOLDER_NAME = "logs";
869601
869802
  var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
869602
869803
  function getCliSource() {
869603
- const version7 = "5.65.4";
869804
+ const version7 = "5.65.6";
869604
869805
  return `cli@${version7}`;
869605
869806
  }
869606
869807
  var DebugLogger = class {
@@ -902162,7 +902363,7 @@ var LegacyDocsPublisher = class {
902162
902363
  previewId,
902163
902364
  disableTemplates: void 0,
902164
902365
  skipUpload,
902165
- cliVersion: "5.65.4",
902366
+ cliVersion: "5.65.6",
902166
902367
  loginCommand: "fern auth login"
902167
902368
  });
902168
902369
  if (taskContext.getResult() === TaskResult.Failure) {
@@ -921740,8 +921941,22 @@ var Generation = class {
921740
921941
  maxRetries: () => this.customConfig.maxRetries,
921741
921942
  /** Controls which HTTP status codes trigger automatic retries. Default: "legacy". */
921742
921943
  retryStatusCodes: () => this.customConfig.retryStatusCodes ?? "legacy",
921743
- /** Override the default request timeout (in seconds) for the generated SDK client. `"infinity"` disables the default timeout. Default: 30. */
921744
- defaultTimeoutInSeconds: () => this.customConfig["default-timeout-in-seconds"],
921944
+ /**
921945
+ * Override the default request timeout (in milliseconds) for the generated SDK client. `"infinity"` disables
921946
+ * the default timeout. Resolves the new `default-timeout-in-milliseconds` key when set, otherwise falls back
921947
+ * to the deprecated `default-timeout-in-seconds` (converted to milliseconds). Default: 30000.
921948
+ */
921949
+ defaultTimeoutInMilliseconds: () => {
921950
+ const milliseconds = this.customConfig["default-timeout-in-milliseconds"];
921951
+ if (milliseconds != null) {
921952
+ return milliseconds;
921953
+ }
921954
+ const seconds = this.customConfig["default-timeout-in-seconds"];
921955
+ if (seconds == null) {
921956
+ return void 0;
921957
+ }
921958
+ return seconds === "infinity" ? "infinity" : seconds * 1e3;
921959
+ },
921745
921960
  /**
921746
921961
  * Output path configuration for generated files.
921747
921962
  * Returns normalized paths for library, test, solution, and other files.
@@ -968472,7 +968687,7 @@ function getAutomationContextFromEnv() {
968472
968687
  config_branch: process.env.FERN_CONFIG_BRANCH,
968473
968688
  config_pr_number: process.env.FERN_CONFIG_PR_NUMBER,
968474
968689
  trigger: process.env.GITHUB_EVENT_NAME,
968475
- cli_version: "5.65.4"
968690
+ cli_version: "5.65.6"
968476
968691
  };
968477
968692
  }
968478
968693
  function isAutomationMode() {
@@ -969304,7 +969519,7 @@ var CliContext = class _CliContext {
969304
969519
  if (false) {
969305
969520
  this.logger.error("CLI_VERSION is not defined");
969306
969521
  }
969307
- return "5.65.4";
969522
+ return "5.65.6";
969308
969523
  }
969309
969524
  getCliName() {
969310
969525
  if (false) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.65.4",
2
+ "version": "5.65.6",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",