@fern-api/fern-api-dev 5.37.4 → 5.37.5

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 +441 -401
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -359502,7 +359502,7 @@ var require_cjs6 = __commonJS({
359502
359502
  return new Promise(function(resolve15, reject) {
359503
359503
  const callback = (err, result) => {
359504
359504
  if (err) {
359505
- return reject(toError(err));
359505
+ return reject(toError2(err));
359506
359506
  }
359507
359507
  resolve15(result);
359508
359508
  };
@@ -359519,7 +359519,7 @@ var require_cjs6 = __commonJS({
359519
359519
  };
359520
359520
  }
359521
359521
  }
359522
- function toError(error50) {
359522
+ function toError2(error50) {
359523
359523
  if (error50 instanceof Error) {
359524
359524
  return error50;
359525
359525
  }
@@ -554898,7 +554898,10 @@ config3(en_default());
554898
554898
  var docs_yml_exports = {};
554899
554899
  __export(docs_yml_exports, {
554900
554900
  DocsYmlSchemas: () => DocsYmlSchemas_exports,
554901
- RawSchemas: () => schemas_exports7
554901
+ RawSchemas: () => schemas_exports7,
554902
+ THEME_ELIGIBLE_FIELDS: () => THEME_ELIGIBLE_FIELDS,
554903
+ THEME_ELIGIBLE_YAML_KEYS: () => THEME_ELIGIBLE_YAML_KEYS,
554904
+ THEME_FIELD_POLICIES: () => THEME_FIELD_POLICIES
554902
554905
  });
554903
554906
 
554904
554907
  // ../configuration/lib/docs-yml/DocsYmlSchemas.js
@@ -559145,6 +559148,33 @@ var VersionFileConfig2 = schemas_exports6.object({
559145
559148
  navigation: NavigationConfig2
559146
559149
  });
559147
559150
 
559151
+ // ../configuration/lib/docs-yml/themeEligibleFields.js
559152
+ var THEME_FIELD_POLICIES = {
559153
+ logo: "global",
559154
+ favicon: "global",
559155
+ backgroundImage: "global",
559156
+ colors: "global",
559157
+ typography: "global",
559158
+ layout: "global",
559159
+ settings: "global",
559160
+ theme: "global",
559161
+ integrations: "global",
559162
+ css: "global",
559163
+ js: "global",
559164
+ header: "global",
559165
+ footer: "global",
559166
+ navbarLinks: "global",
559167
+ footerLinks: "global",
559168
+ aiSearch: "global",
559169
+ announcement: "global",
559170
+ metadata: "global"
559171
+ };
559172
+ var THEME_ELIGIBLE_FIELDS = Object.keys(THEME_FIELD_POLICIES);
559173
+ function camelToKebab(value2) {
559174
+ return value2.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
559175
+ }
559176
+ var THEME_ELIGIBLE_YAML_KEYS = new Set(THEME_ELIGIBLE_FIELDS.map(camelToKebab));
559177
+
559148
559178
  // ../configuration/lib/fernignoreUtils.js
559149
559179
  var import_promises10 = require("fs/promises");
559150
559180
  var NEW_LINE_REGEX = /\r?\n/;
@@ -602213,14 +602243,14 @@ var IntermediateRepresentationChangeDetector = class {
602213
602243
  }
602214
602244
  checkErrorsBreakingChanges({ from: from4, to: to10 }) {
602215
602245
  for (const [_7, fromError] of Object.entries(from4)) {
602216
- const toError = Object.values(to10).find((error50) => error50.name.errorId === fromError.name.errorId);
602217
- if (!toError) {
602246
+ const toError2 = Object.values(to10).find((error50) => error50.name.errorId === fromError.name.errorId);
602247
+ if (!toError2) {
602218
602248
  this.errors.add(`Error "${fromError.name.errorId}" with status code "${fromError.statusCode}" was removed.`);
602219
602249
  continue;
602220
602250
  }
602221
602251
  this.checkErrorBreakingChanges({
602222
602252
  from: fromError,
602223
- to: toError
602253
+ to: toError2
602224
602254
  });
602225
602255
  }
602226
602256
  }
@@ -669171,7 +669201,7 @@ var AccessTokenPosthogManager = class {
669171
669201
  properties: {
669172
669202
  ...event,
669173
669203
  ...event.properties,
669174
- version: "5.37.4",
669204
+ version: "5.37.5",
669175
669205
  usingAccessToken: true,
669176
669206
  ...getRunIdProperties()
669177
669207
  }
@@ -669235,7 +669265,7 @@ var UserPosthogManager = class {
669235
669265
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
669236
669266
  event: "CLI",
669237
669267
  properties: {
669238
- version: "5.37.4",
669268
+ version: "5.37.5",
669239
669269
  ...event,
669240
669270
  ...event.properties,
669241
669271
  usingAccessToken: false,
@@ -827313,27 +827343,7 @@ function deepMergeGlobalWins(local, global3) {
827313
827343
  }
827314
827344
  return result;
827315
827345
  }
827316
- var THEME_FIELD_POLICIES = {
827317
- logo: "global",
827318
- favicon: "global",
827319
- backgroundImage: "global",
827320
- colors: "global",
827321
- typography: "global",
827322
- layout: "global",
827323
- settings: "global",
827324
- theme: "global",
827325
- integrations: "global",
827326
- css: "global",
827327
- js: "global",
827328
- header: "global",
827329
- footer: "global",
827330
- navbarLinks: "global",
827331
- footerLinks: "global",
827332
- aiSearch: "global",
827333
- announcement: "global",
827334
- metadata: "global"
827335
- };
827336
- var THEME_ELIGIBLE_KEYS = Object.keys(THEME_FIELD_POLICIES);
827346
+ var { THEME_ELIGIBLE_FIELDS: THEME_ELIGIBLE_FIELDS2, THEME_FIELD_POLICIES: THEME_FIELD_POLICIES2 } = docs_yml_exports;
827337
827347
  function kebabToCamel(str3) {
827338
827348
  return str3.replace(/-([a-z])/g, (_7, c6) => c6.toUpperCase());
827339
827349
  }
@@ -827358,10 +827368,10 @@ function mergeThemeOverride(local, themeOverride) {
827358
827368
  const normalized = normalizeThemeKeys(themeOverride);
827359
827369
  const localRecord = local;
827360
827370
  const merged = { ...localRecord };
827361
- for (const key2 of THEME_ELIGIBLE_KEYS) {
827371
+ for (const key2 of THEME_ELIGIBLE_FIELDS2) {
827362
827372
  const themeValue = normalized[key2];
827363
827373
  const localValue = localRecord[key2];
827364
- const policy = THEME_FIELD_POLICIES[key2] ?? "global";
827374
+ const policy = THEME_FIELD_POLICIES2[key2] ?? "global";
827365
827375
  const themeHasValue = themeValue !== void 0 && themeValue !== null;
827366
827376
  const localHasValue = localValue !== void 0 && localValue !== null;
827367
827377
  if (policy === "global") {
@@ -860076,6 +860086,352 @@ var import_fs30 = __toESM(require("fs"), 1);
860076
860086
  var import_promises97 = require("fs/promises");
860077
860087
  var import_http9 = __toESM(require("http"), 1);
860078
860088
  var import_path69 = __toESM(require("path"), 1);
860089
+ init_wrapper();
860090
+
860091
+ // ../docs-preview/lib/DebugLogger.js
860092
+ init_lib8();
860093
+ var import_promises94 = require("fs/promises");
860094
+ var import_os9 = require("os");
860095
+ var import_path66 = __toESM(require("path"), 1);
860096
+ var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
860097
+ var LOGS_FOLDER_NAME = "logs";
860098
+ var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
860099
+ function getCliSource() {
860100
+ const version7 = "5.37.5";
860101
+ return `cli@${version7}`;
860102
+ }
860103
+ var DebugLogger = class {
860104
+ logFilePath = null;
860105
+ initialized = false;
860106
+ sessionStartTime;
860107
+ consoleLogger;
860108
+ constructor() {
860109
+ this.sessionStartTime = Date.now();
860110
+ }
860111
+ /**
860112
+ * Initialize the debug logger by creating the log file
860113
+ */
860114
+ async initialize(consoleLogger, logsDir) {
860115
+ if (this.initialized) {
860116
+ return;
860117
+ }
860118
+ this.consoleLogger = consoleLogger;
860119
+ const resolvedLogsDir = logsDir ?? join8(join8(AbsoluteFilePath2.of((0, import_os9.homedir)()), RelativeFilePath2.of(LOCAL_STORAGE_FOLDER4)), RelativeFilePath2.of(LOGS_FOLDER_NAME));
860120
+ if (!await doesPathExist(resolvedLogsDir)) {
860121
+ await (0, import_promises94.mkdir)(resolvedLogsDir, { recursive: true });
860122
+ }
860123
+ const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
860124
+ const logFileName = `${timestamp2}.debug.log`;
860125
+ this.logFilePath = join8(resolvedLogsDir, RelativeFilePath2.of(logFileName));
860126
+ const header = [
860127
+ "================================================================================",
860128
+ `Fern Docs Dev Debug Log`,
860129
+ `Session started: ${(/* @__PURE__ */ new Date()).toISOString()}`,
860130
+ `Log file: ${import_path66.default.basename(this.logFilePath)}`,
860131
+ "================================================================================",
860132
+ ""
860133
+ ].join("\n");
860134
+ await (0, import_promises94.writeFile)(this.logFilePath, header, "utf-8");
860135
+ this.initialized = true;
860136
+ void this.enforceLogSizeLimit(resolvedLogsDir);
860137
+ }
860138
+ /**
860139
+ * Get the path to the log file
860140
+ */
860141
+ getLogFilePath() {
860142
+ return this.logFilePath;
860143
+ }
860144
+ /**
860145
+ * Write a log entry to the debug file
860146
+ */
860147
+ async writeEntry(entry) {
860148
+ if (!this.initialized || !this.logFilePath) {
860149
+ return;
860150
+ }
860151
+ const line = JSON.stringify(entry) + "\n";
860152
+ try {
860153
+ await (0, import_promises94.appendFile)(this.logFilePath, line, "utf-8");
860154
+ } catch (error50) {
860155
+ }
860156
+ }
860157
+ /**
860158
+ * Log a frontend metrics message
860159
+ */
860160
+ async logFrontendMetrics(message) {
860161
+ const entry = {
860162
+ timestamp: message.timestamp,
860163
+ source: message.source,
860164
+ level: message.level,
860165
+ eventType: this.getEventType(message.payload, message.isAggregate),
860166
+ isAggregate: message.isAggregate,
860167
+ data: message.payload
860168
+ };
860169
+ await this.writeEntry(entry);
860170
+ }
860171
+ /**
860172
+ * Log a CLI-side metric event
860173
+ */
860174
+ async logCliMetric(event, level = "info") {
860175
+ const entry = {
860176
+ timestamp: event.timestamp,
860177
+ source: getCliSource(),
860178
+ level,
860179
+ eventType: event.type,
860180
+ data: {
860181
+ durationMs: event.durationMs,
860182
+ metadata: event.metadata
860183
+ }
860184
+ };
860185
+ await this.writeEntry(entry);
860186
+ }
860187
+ /**
860188
+ * Log CLI memory usage
860189
+ */
860190
+ async logCliMemory() {
860191
+ const memUsage = process.memoryUsage();
860192
+ const event = {
860193
+ type: "cli_memory",
860194
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
860195
+ metadata: {
860196
+ heapUsed: memUsage.heapUsed,
860197
+ heapTotal: memUsage.heapTotal,
860198
+ external: memUsage.external,
860199
+ rss: memUsage.rss,
860200
+ heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024 * 100) / 100,
860201
+ heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024 * 100) / 100,
860202
+ rssMB: Math.round(memUsage.rss / 1024 / 1024 * 100) / 100
860203
+ }
860204
+ };
860205
+ await this.logCliMetric(event);
860206
+ }
860207
+ /**
860208
+ * Log CLI reload start
860209
+ */
860210
+ async logCliReloadStart() {
860211
+ const event = {
860212
+ type: "cli_reload_start",
860213
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
860214
+ };
860215
+ await this.logCliMetric(event);
860216
+ }
860217
+ /**
860218
+ * Log CLI reload finish with duration
860219
+ */
860220
+ async logCliReloadFinish(durationMs, metadata) {
860221
+ const event = {
860222
+ type: "cli_reload_finish",
860223
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
860224
+ durationMs,
860225
+ metadata
860226
+ };
860227
+ await this.logCliMetric(event);
860228
+ }
860229
+ /**
860230
+ * Log CLI docs generation time
860231
+ */
860232
+ async logCliDocsGeneration(durationMs, metadata) {
860233
+ const event = {
860234
+ type: "cli_docs_generation",
860235
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
860236
+ durationMs,
860237
+ metadata
860238
+ };
860239
+ await this.logCliMetric(event);
860240
+ }
860241
+ /**
860242
+ * Log CLI validation time
860243
+ */
860244
+ async logCliValidation(durationMs, success2) {
860245
+ const event = {
860246
+ type: "cli_validation",
860247
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
860248
+ durationMs,
860249
+ metadata: { success: success2 }
860250
+ };
860251
+ await this.logCliMetric(event);
860252
+ }
860253
+ /**
860254
+ * Delete oldest log files until total directory size is within the cap.
860255
+ */
860256
+ async enforceLogSizeLimit(logsDir) {
860257
+ try {
860258
+ const entries24 = await (0, import_promises94.readdir)(logsDir);
860259
+ const logFiles = entries24.filter((name2) => name2.endsWith(".log"));
860260
+ const fileInfos = [];
860261
+ for (const name2 of logFiles) {
860262
+ const fullPath = import_path66.default.join(logsDir, name2);
860263
+ try {
860264
+ const stats = await (0, import_promises94.stat)(fullPath);
860265
+ fileInfos.push({ name: name2, fullPath, size: stats.size, mtimeMs: stats.mtimeMs });
860266
+ } catch {
860267
+ }
860268
+ }
860269
+ let totalSize = fileInfos.reduce((sum, f4) => sum + f4.size, 0);
860270
+ const totalSizeMB = Math.round(totalSize / 1024 / 1024 * 100) / 100;
860271
+ const capMB = MAX_LOGS_DIR_SIZE_BYTES / 1024 / 1024;
860272
+ if (totalSize <= MAX_LOGS_DIR_SIZE_BYTES) {
860273
+ this.consoleLogger?.debug(`Log directory size ${totalSizeMB} MB does not exceed ${capMB} MB cap`);
860274
+ return;
860275
+ }
860276
+ this.consoleLogger?.info(`Rotating logs: total size ${totalSizeMB} MB exceeds ${capMB} MB cap`);
860277
+ fileInfos.sort((a3, b8) => a3.mtimeMs - b8.mtimeMs);
860278
+ for (const file4 of fileInfos) {
860279
+ if (totalSize <= MAX_LOGS_DIR_SIZE_BYTES) {
860280
+ break;
860281
+ }
860282
+ if (this.logFilePath != null && file4.fullPath === this.logFilePath) {
860283
+ continue;
860284
+ }
860285
+ try {
860286
+ await (0, import_promises94.unlink)(file4.fullPath);
860287
+ totalSize -= file4.size;
860288
+ } catch {
860289
+ }
860290
+ }
860291
+ } catch {
860292
+ }
860293
+ }
860294
+ getEventType(payload, isAggregate) {
860295
+ if (isAggregate) {
860296
+ return "aggregate_summary";
860297
+ }
860298
+ if ("type" in payload && typeof payload.type === "string") {
860299
+ return payload.type;
860300
+ }
860301
+ return "unknown";
860302
+ }
860303
+ /**
860304
+ * Check if a WebSocket message is a metrics message
860305
+ */
860306
+ static isMetricsMessage(data2) {
860307
+ if (typeof data2 !== "object" || data2 === null) {
860308
+ return false;
860309
+ }
860310
+ const obj = data2;
860311
+ return obj.type === "metrics" && typeof obj.timestamp === "string" && typeof obj.source === "string";
860312
+ }
860313
+ };
860314
+
860315
+ // ../docs-preview/lib/createBunServer.js
860316
+ var CORS_HEADERS = {
860317
+ "Access-Control-Allow-Origin": "*",
860318
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
860319
+ "Access-Control-Allow-Headers": "Content-Type"
860320
+ };
860321
+ function createBunServer(options2) {
860322
+ const bun = getBun();
860323
+ if (bun == null) {
860324
+ return void 0;
860325
+ }
860326
+ const { port, debugLogger, getDocsLoadResponse, extractLocaleFromPath } = options2;
860327
+ const connections = /* @__PURE__ */ new Map();
860328
+ function sendData(data2) {
860329
+ const message = JSON.stringify(data2);
860330
+ const dead = [];
860331
+ for (const [ws5] of connections) {
860332
+ try {
860333
+ ws5.send(message);
860334
+ } catch {
860335
+ dead.push(ws5);
860336
+ }
860337
+ }
860338
+ for (const ws5 of dead) {
860339
+ const metadata = connections.get(ws5);
860340
+ if (metadata) {
860341
+ clearInterval(metadata.pingInterval);
860342
+ connections.delete(ws5);
860343
+ }
860344
+ }
860345
+ }
860346
+ const server = bun.serve({
860347
+ port,
860348
+ async fetch(req, bunHttpServer) {
860349
+ if (req.method === "OPTIONS") {
860350
+ return new Response(null, { status: 204, headers: CORS_HEADERS });
860351
+ }
860352
+ const url3 = new URL(req.url);
860353
+ if (req.headers.get("upgrade")?.toLowerCase() === "websocket") {
860354
+ bunHttpServer.upgrade(req, { data: { connectionId: `${Date.now()}` } });
860355
+ return void 0;
860356
+ }
860357
+ if (req.method === "POST" && url3.pathname === "/v2/registry/docs/load-with-url") {
860358
+ try {
860359
+ const body = await req.json();
860360
+ const locale = extractLocaleFromPath?.(body?.url);
860361
+ return new Response(JSON.stringify(getDocsLoadResponse(locale)), {
860362
+ headers: { "Content-Type": "application/json", ...CORS_HEADERS }
860363
+ });
860364
+ } catch {
860365
+ return new Response(JSON.stringify(getDocsLoadResponse()), {
860366
+ headers: { "Content-Type": "application/json", ...CORS_HEADERS }
860367
+ });
860368
+ }
860369
+ }
860370
+ const localMatch = /^\/_local\/(.*)/.exec(url3.pathname);
860371
+ if (req.method === "GET" && localMatch != null) {
860372
+ return new Response(bun.file(`/${localMatch[1]}`), { headers: CORS_HEADERS });
860373
+ }
860374
+ return new Response("Not Found", { status: 404 });
860375
+ },
860376
+ websocket: {
860377
+ open(ws5) {
860378
+ const { connectionId } = ws5.data;
860379
+ const pingInterval = setInterval(() => {
860380
+ const metadata = connections.get(ws5);
860381
+ if (!metadata) {
860382
+ return;
860383
+ }
860384
+ const now = Date.now();
860385
+ if (now - metadata.lastPong > 9e4) {
860386
+ ws5.close();
860387
+ return;
860388
+ }
860389
+ try {
860390
+ ws5.send(JSON.stringify({ type: "ping", timestamp: now }));
860391
+ } catch {
860392
+ ws5.close();
860393
+ }
860394
+ }, 3e4);
860395
+ connections.set(ws5, { pingInterval, lastPong: Date.now() });
860396
+ try {
860397
+ ws5.send(JSON.stringify({ type: "connected", connectionId }));
860398
+ } catch {
860399
+ }
860400
+ },
860401
+ message(ws5, data2) {
860402
+ try {
860403
+ const parsed = JSON.parse(data2.toString());
860404
+ if (parsed.type === "pong") {
860405
+ const metadata = connections.get(ws5);
860406
+ if (metadata) {
860407
+ metadata.lastPong = Date.now();
860408
+ }
860409
+ } else if (DebugLogger.isMetricsMessage(parsed)) {
860410
+ void debugLogger.logFrontendMetrics(parsed);
860411
+ }
860412
+ } catch {
860413
+ }
860414
+ },
860415
+ close(ws5) {
860416
+ const metadata = connections.get(ws5);
860417
+ if (metadata) {
860418
+ clearInterval(metadata.pingInterval);
860419
+ connections.delete(ws5);
860420
+ }
860421
+ }
860422
+ }
860423
+ });
860424
+ return {
860425
+ sendData,
860426
+ stop: (closeActiveConnections) => server.stop(closeActiveConnections)
860427
+ };
860428
+ }
860429
+ function getBun() {
860430
+ return globalThis.Bun;
860431
+ }
860432
+
860433
+ // ../docs-preview/lib/createDocsPreviewWatcher.js
860434
+ init_lib6();
860079
860435
 
860080
860436
  // ../../../node_modules/.pnpm/watcher@2.3.1/node_modules/watcher/dist/watcher.js
860081
860437
  var import_node_events7 = require("events");
@@ -860489,7 +860845,7 @@ var isFunction8 = (value2) => {
860489
860845
  };
860490
860846
 
860491
860847
  // ../../../node_modules/.pnpm/tiny-readdir@2.7.4/node_modules/tiny-readdir/dist/index.js
860492
- var readdir13 = (rootPath, options2) => {
860848
+ var readdir14 = (rootPath, options2) => {
860493
860849
  const followSymlinks = options2?.followSymlinks ?? false;
860494
860850
  const maxDepth = options2?.depth ?? Infinity;
860495
860851
  const maxPaths = options2?.limit ?? Infinity;
@@ -860655,7 +861011,7 @@ var readdir13 = (rootPath, options2) => {
860655
861011
  };
860656
861012
  return populateResultFromRoot(rootPath);
860657
861013
  };
860658
- var dist_default4 = readdir13;
861014
+ var dist_default4 = readdir14;
860659
861015
 
860660
861016
  // ../../../node_modules/.pnpm/watcher@2.3.1/node_modules/watcher/dist/utils.js
860661
861017
  var Utils = {
@@ -861741,349 +862097,52 @@ var Watcher = class _Watcher extends import_node_events7.EventEmitter {
861741
862097
  };
861742
862098
  var watcher_default = Watcher;
861743
862099
 
861744
- // ../docs-preview/lib/runAppPreviewServer.js
861745
- init_wrapper();
861746
-
861747
- // ../docs-preview/lib/DebugLogger.js
861748
- init_lib8();
861749
- var import_promises94 = require("fs/promises");
861750
- var import_os9 = require("os");
861751
- var import_path66 = __toESM(require("path"), 1);
861752
- var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
861753
- var LOGS_FOLDER_NAME = "logs";
861754
- var MAX_LOGS_DIR_SIZE_BYTES = 100 * 1024 * 1024;
861755
- function getCliSource() {
861756
- const version7 = "5.37.4";
861757
- return `cli@${version7}`;
862100
+ // ../docs-preview/lib/createDocsPreviewWatcher.js
862101
+ function isErrnoError(error50) {
862102
+ return "code" in error50 && typeof error50.code === "string";
861758
862103
  }
861759
- var DebugLogger = class {
861760
- logFilePath = null;
861761
- initialized = false;
861762
- sessionStartTime;
861763
- consoleLogger;
861764
- constructor() {
861765
- this.sessionStartTime = Date.now();
861766
- }
861767
- /**
861768
- * Initialize the debug logger by creating the log file
861769
- */
861770
- async initialize(consoleLogger, logsDir) {
861771
- if (this.initialized) {
861772
- return;
861773
- }
861774
- this.consoleLogger = consoleLogger;
861775
- const resolvedLogsDir = logsDir ?? join8(join8(AbsoluteFilePath2.of((0, import_os9.homedir)()), RelativeFilePath2.of(LOCAL_STORAGE_FOLDER4)), RelativeFilePath2.of(LOGS_FOLDER_NAME));
861776
- if (!await doesPathExist(resolvedLogsDir)) {
861777
- await (0, import_promises94.mkdir)(resolvedLogsDir, { recursive: true });
861778
- }
861779
- const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
861780
- const logFileName = `${timestamp2}.debug.log`;
861781
- this.logFilePath = join8(resolvedLogsDir, RelativeFilePath2.of(logFileName));
861782
- const header = [
861783
- "================================================================================",
861784
- `Fern Docs Dev Debug Log`,
861785
- `Session started: ${(/* @__PURE__ */ new Date()).toISOString()}`,
861786
- `Log file: ${import_path66.default.basename(this.logFilePath)}`,
861787
- "================================================================================",
861788
- ""
861789
- ].join("\n");
861790
- await (0, import_promises94.writeFile)(this.logFilePath, header, "utf-8");
861791
- this.initialized = true;
861792
- void this.enforceLogSizeLimit(resolvedLogsDir);
861793
- }
861794
- /**
861795
- * Get the path to the log file
861796
- */
861797
- getLogFilePath() {
861798
- return this.logFilePath;
861799
- }
861800
- /**
861801
- * Write a log entry to the debug file
861802
- */
861803
- async writeEntry(entry) {
861804
- if (!this.initialized || !this.logFilePath) {
861805
- return;
861806
- }
861807
- const line = JSON.stringify(entry) + "\n";
861808
- try {
861809
- await (0, import_promises94.appendFile)(this.logFilePath, line, "utf-8");
861810
- } catch (error50) {
861811
- }
861812
- }
861813
- /**
861814
- * Log a frontend metrics message
861815
- */
861816
- async logFrontendMetrics(message) {
861817
- const entry = {
861818
- timestamp: message.timestamp,
861819
- source: message.source,
861820
- level: message.level,
861821
- eventType: this.getEventType(message.payload, message.isAggregate),
861822
- isAggregate: message.isAggregate,
861823
- data: message.payload
861824
- };
861825
- await this.writeEntry(entry);
861826
- }
861827
- /**
861828
- * Log a CLI-side metric event
861829
- */
861830
- async logCliMetric(event, level = "info") {
861831
- const entry = {
861832
- timestamp: event.timestamp,
861833
- source: getCliSource(),
861834
- level,
861835
- eventType: event.type,
861836
- data: {
861837
- durationMs: event.durationMs,
861838
- metadata: event.metadata
861839
- }
861840
- };
861841
- await this.writeEntry(entry);
861842
- }
861843
- /**
861844
- * Log CLI memory usage
861845
- */
861846
- async logCliMemory() {
861847
- const memUsage = process.memoryUsage();
861848
- const event = {
861849
- type: "cli_memory",
861850
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
861851
- metadata: {
861852
- heapUsed: memUsage.heapUsed,
861853
- heapTotal: memUsage.heapTotal,
861854
- external: memUsage.external,
861855
- rss: memUsage.rss,
861856
- heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024 * 100) / 100,
861857
- heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024 * 100) / 100,
861858
- rssMB: Math.round(memUsage.rss / 1024 / 1024 * 100) / 100
861859
- }
861860
- };
861861
- await this.logCliMetric(event);
861862
- }
861863
- /**
861864
- * Log CLI reload start
861865
- */
861866
- async logCliReloadStart() {
861867
- const event = {
861868
- type: "cli_reload_start",
861869
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
861870
- };
861871
- await this.logCliMetric(event);
861872
- }
861873
- /**
861874
- * Log CLI reload finish with duration
861875
- */
861876
- async logCliReloadFinish(durationMs, metadata) {
861877
- const event = {
861878
- type: "cli_reload_finish",
861879
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
861880
- durationMs,
861881
- metadata
861882
- };
861883
- await this.logCliMetric(event);
862104
+ function toError(error50) {
862105
+ return error50 instanceof Error ? error50 : new Error(String(error50));
862106
+ }
862107
+ function getWatcherErrorMessage(error50) {
862108
+ if (isErrnoError(error50) && error50.code === "ENOSPC") {
862109
+ return "Unable to watch Fern docs files for changes because the system limit for file watchers was reached. Close other file-watching processes or increase the file watcher limit, then restart `fern docs dev`.";
861884
862110
  }
861885
- /**
861886
- * Log CLI docs generation time
861887
- */
861888
- async logCliDocsGeneration(durationMs, metadata) {
861889
- const event = {
861890
- type: "cli_docs_generation",
861891
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
861892
- durationMs,
861893
- metadata
862111
+ return `Unable to watch Fern docs files for changes: ${error50.message}`;
862112
+ }
862113
+ async function createDocsPreviewWatcher({ absoluteFilePathToFern, additionalFilepaths, context: context3 }) {
862114
+ const watcher = new watcher_default([absoluteFilePathToFern, ...additionalFilepaths], {
862115
+ recursive: true,
862116
+ ignoreInitial: true,
862117
+ debounce: 100,
862118
+ renameDetection: true
862119
+ });
862120
+ const initializationError = await new Promise((resolve15) => {
862121
+ const handleReady = () => {
862122
+ watcher.off("error", handleError3);
862123
+ resolve15(void 0);
861894
862124
  };
861895
- await this.logCliMetric(event);
861896
- }
861897
- /**
861898
- * Log CLI validation time
861899
- */
861900
- async logCliValidation(durationMs, success2) {
861901
- const event = {
861902
- type: "cli_validation",
861903
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
861904
- durationMs,
861905
- metadata: { success: success2 }
862125
+ const handleError3 = (error50) => {
862126
+ watcher.off("ready", handleReady);
862127
+ resolve15(toError(error50));
861906
862128
  };
861907
- await this.logCliMetric(event);
861908
- }
861909
- /**
861910
- * Delete oldest log files until total directory size is within the cap.
861911
- */
861912
- async enforceLogSizeLimit(logsDir) {
861913
- try {
861914
- const entries24 = await (0, import_promises94.readdir)(logsDir);
861915
- const logFiles = entries24.filter((name2) => name2.endsWith(".log"));
861916
- const fileInfos = [];
861917
- for (const name2 of logFiles) {
861918
- const fullPath = import_path66.default.join(logsDir, name2);
861919
- try {
861920
- const stats = await (0, import_promises94.stat)(fullPath);
861921
- fileInfos.push({ name: name2, fullPath, size: stats.size, mtimeMs: stats.mtimeMs });
861922
- } catch {
861923
- }
861924
- }
861925
- let totalSize = fileInfos.reduce((sum, f4) => sum + f4.size, 0);
861926
- const totalSizeMB = Math.round(totalSize / 1024 / 1024 * 100) / 100;
861927
- const capMB = MAX_LOGS_DIR_SIZE_BYTES / 1024 / 1024;
861928
- if (totalSize <= MAX_LOGS_DIR_SIZE_BYTES) {
861929
- this.consoleLogger?.debug(`Log directory size ${totalSizeMB} MB does not exceed ${capMB} MB cap`);
861930
- return;
861931
- }
861932
- this.consoleLogger?.info(`Rotating logs: total size ${totalSizeMB} MB exceeds ${capMB} MB cap`);
861933
- fileInfos.sort((a3, b8) => a3.mtimeMs - b8.mtimeMs);
861934
- for (const file4 of fileInfos) {
861935
- if (totalSize <= MAX_LOGS_DIR_SIZE_BYTES) {
861936
- break;
861937
- }
861938
- if (this.logFilePath != null && file4.fullPath === this.logFilePath) {
861939
- continue;
861940
- }
861941
- try {
861942
- await (0, import_promises94.unlink)(file4.fullPath);
861943
- totalSize -= file4.size;
861944
- } catch {
861945
- }
861946
- }
861947
- } catch {
861948
- }
861949
- }
861950
- getEventType(payload, isAggregate) {
861951
- if (isAggregate) {
861952
- return "aggregate_summary";
861953
- }
861954
- if ("type" in payload && typeof payload.type === "string") {
861955
- return payload.type;
861956
- }
861957
- return "unknown";
861958
- }
861959
- /**
861960
- * Check if a WebSocket message is a metrics message
861961
- */
861962
- static isMetricsMessage(data2) {
861963
- if (typeof data2 !== "object" || data2 === null) {
861964
- return false;
861965
- }
861966
- const obj = data2;
861967
- return obj.type === "metrics" && typeof obj.timestamp === "string" && typeof obj.source === "string";
861968
- }
861969
- };
861970
-
861971
- // ../docs-preview/lib/createBunServer.js
861972
- var CORS_HEADERS = {
861973
- "Access-Control-Allow-Origin": "*",
861974
- "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
861975
- "Access-Control-Allow-Headers": "Content-Type"
861976
- };
861977
- function createBunServer(options2) {
861978
- const bun = getBun();
861979
- if (bun == null) {
861980
- return void 0;
861981
- }
861982
- const { port, debugLogger, getDocsLoadResponse, extractLocaleFromPath } = options2;
861983
- const connections = /* @__PURE__ */ new Map();
861984
- function sendData(data2) {
861985
- const message = JSON.stringify(data2);
861986
- const dead = [];
861987
- for (const [ws5] of connections) {
861988
- try {
861989
- ws5.send(message);
861990
- } catch {
861991
- dead.push(ws5);
861992
- }
861993
- }
861994
- for (const ws5 of dead) {
861995
- const metadata = connections.get(ws5);
861996
- if (metadata) {
861997
- clearInterval(metadata.pingInterval);
861998
- connections.delete(ws5);
861999
- }
862000
- }
862129
+ watcher.once("ready", handleReady);
862130
+ watcher.once("error", handleError3);
862131
+ });
862132
+ if (initializationError != null) {
862133
+ watcher.close();
862134
+ context3.failAndThrow(getWatcherErrorMessage(initializationError), initializationError, {
862135
+ code: CliError.Code.EnvironmentError
862136
+ });
862001
862137
  }
862002
- const server = bun.serve({
862003
- port,
862004
- async fetch(req, bunHttpServer) {
862005
- if (req.method === "OPTIONS") {
862006
- return new Response(null, { status: 204, headers: CORS_HEADERS });
862007
- }
862008
- const url3 = new URL(req.url);
862009
- if (req.headers.get("upgrade")?.toLowerCase() === "websocket") {
862010
- bunHttpServer.upgrade(req, { data: { connectionId: `${Date.now()}` } });
862011
- return void 0;
862012
- }
862013
- if (req.method === "POST" && url3.pathname === "/v2/registry/docs/load-with-url") {
862014
- try {
862015
- const body = await req.json();
862016
- const locale = extractLocaleFromPath?.(body?.url);
862017
- return new Response(JSON.stringify(getDocsLoadResponse(locale)), {
862018
- headers: { "Content-Type": "application/json", ...CORS_HEADERS }
862019
- });
862020
- } catch {
862021
- return new Response(JSON.stringify(getDocsLoadResponse()), {
862022
- headers: { "Content-Type": "application/json", ...CORS_HEADERS }
862023
- });
862024
- }
862025
- }
862026
- const localMatch = /^\/_local\/(.*)/.exec(url3.pathname);
862027
- if (req.method === "GET" && localMatch != null) {
862028
- return new Response(bun.file(`/${localMatch[1]}`), { headers: CORS_HEADERS });
862029
- }
862030
- return new Response("Not Found", { status: 404 });
862031
- },
862032
- websocket: {
862033
- open(ws5) {
862034
- const { connectionId } = ws5.data;
862035
- const pingInterval = setInterval(() => {
862036
- const metadata = connections.get(ws5);
862037
- if (!metadata) {
862038
- return;
862039
- }
862040
- const now = Date.now();
862041
- if (now - metadata.lastPong > 9e4) {
862042
- ws5.close();
862043
- return;
862044
- }
862045
- try {
862046
- ws5.send(JSON.stringify({ type: "ping", timestamp: now }));
862047
- } catch {
862048
- ws5.close();
862049
- }
862050
- }, 3e4);
862051
- connections.set(ws5, { pingInterval, lastPong: Date.now() });
862052
- try {
862053
- ws5.send(JSON.stringify({ type: "connected", connectionId }));
862054
- } catch {
862055
- }
862056
- },
862057
- message(ws5, data2) {
862058
- try {
862059
- const parsed = JSON.parse(data2.toString());
862060
- if (parsed.type === "pong") {
862061
- const metadata = connections.get(ws5);
862062
- if (metadata) {
862063
- metadata.lastPong = Date.now();
862064
- }
862065
- } else if (DebugLogger.isMetricsMessage(parsed)) {
862066
- void debugLogger.logFrontendMetrics(parsed);
862067
- }
862068
- } catch {
862069
- }
862070
- },
862071
- close(ws5) {
862072
- const metadata = connections.get(ws5);
862073
- if (metadata) {
862074
- clearInterval(metadata.pingInterval);
862075
- connections.delete(ws5);
862076
- }
862077
- }
862078
- }
862138
+ watcher.on("error", (error50) => {
862139
+ const watcherError = toError(error50);
862140
+ context3.failWithoutThrowing(getWatcherErrorMessage(watcherError), watcherError, {
862141
+ code: CliError.Code.EnvironmentError
862142
+ });
862143
+ watcher.close();
862079
862144
  });
862080
- return {
862081
- sendData,
862082
- stop: (closeActiveConnections) => server.stop(closeActiveConnections)
862083
- };
862084
- }
862085
- function getBun() {
862086
- return globalThis.Bun;
862145
+ return watcher;
862087
862146
  }
862088
862147
 
862089
862148
  // ../docs-preview/lib/downloadLocalDocsBundle.js
@@ -863724,11 +863783,10 @@ ${err.stack}`);
863724
863783
  slugTracker.initialize(previewResult.docsDefinition);
863725
863784
  }
863726
863785
  const additionalFilepaths = project.apiWorkspaces.flatMap((workspace) => workspace.getAbsoluteFilePaths());
863727
- const watcher = new watcher_default([absoluteFilePathToFern, ...additionalFilepaths], {
863728
- recursive: true,
863729
- ignoreInitial: true,
863730
- debounce: 100,
863731
- renameDetection: true
863786
+ const watcher = await createDocsPreviewWatcher({
863787
+ absoluteFilePathToFern,
863788
+ additionalFilepaths,
863789
+ context: context3
863732
863790
  });
863733
863791
  const editedAbsoluteFilepaths = [];
863734
863792
  function extractLocaleFromPath(urlPath) {
@@ -864287,11 +864345,10 @@ ${err.stack}`);
864287
864345
  }
864288
864346
  const additionalFilepaths = project.apiWorkspaces.flatMap((workspace) => workspace.getAbsoluteFilePaths());
864289
864347
  const bundleRoot = bundlePath ? AbsoluteFilePath2.of(import_path70.default.resolve(bundlePath)) : getPathToBundleFolder({ cacheDir });
864290
- const watcher = new watcher_default([absoluteFilePathToFern, ...additionalFilepaths], {
864291
- recursive: true,
864292
- ignoreInitial: true,
864293
- debounce: 100,
864294
- renameDetection: true
864348
+ const watcher = await createDocsPreviewWatcher({
864349
+ absoluteFilePathToFern,
864350
+ additionalFilepaths,
864351
+ context: context3
864295
864352
  });
864296
864353
  const editedAbsoluteFilepaths = [];
864297
864354
  watcher.on("all", async (event, targetPath, _targetPathNext) => {
@@ -880641,7 +880698,7 @@ var LegacyDocsPublisher = class {
880641
880698
  previewId,
880642
880699
  disableTemplates: void 0,
880643
880700
  skipUpload,
880644
- cliVersion: "5.37.4",
880701
+ cliVersion: "5.37.5",
880645
880702
  loginCommand: "fern auth login"
880646
880703
  });
880647
880704
  if (taskContext.getResult() === TaskResult.Failure) {
@@ -955562,7 +955619,7 @@ function getAutomationContextFromEnv() {
955562
955619
  config_branch: process.env.FERN_CONFIG_BRANCH,
955563
955620
  config_pr_number: process.env.FERN_CONFIG_PR_NUMBER,
955564
955621
  trigger: process.env.GITHUB_EVENT_NAME,
955565
- cli_version: "5.37.4"
955622
+ cli_version: "5.37.5"
955566
955623
  };
955567
955624
  }
955568
955625
  function isAutomationMode() {
@@ -956388,7 +956445,7 @@ var CliContext = class _CliContext {
956388
956445
  if (false) {
956389
956446
  this.logger.error("CLI_VERSION is not defined");
956390
956447
  }
956391
- return "5.37.4";
956448
+ return "5.37.5";
956392
956449
  }
956393
956450
  getCliName() {
956394
956451
  if (false) {
@@ -965120,23 +965177,6 @@ init_lib8();
965120
965177
  var import_promises189 = require("fs/promises");
965121
965178
  init_js_yaml();
965122
965179
  var import_path105 = __toESM(require("path"), 1);
965123
- var THEME_ELIGIBLE_KEYS2 = /* @__PURE__ */ new Set([
965124
- "logo",
965125
- "favicon",
965126
- "colors",
965127
- "typography",
965128
- "layout",
965129
- "navbar-links",
965130
- "footer-links",
965131
- "background-image",
965132
- "theme",
965133
- "css",
965134
- "js",
965135
- "header",
965136
- "footer",
965137
- "metadata",
965138
- "settings"
965139
- ]);
965140
965180
  var ThemeExporter = class {
965141
965181
  constructor(docsWorkspace) {
965142
965182
  this.docsWorkspace = docsWorkspace;
@@ -965150,7 +965190,7 @@ var ThemeExporter = class {
965150
965190
  const raw = jsYaml.load(await (0, import_promises189.readFile)(docsYmlPath, "utf-8"));
965151
965191
  const themeConfig = {};
965152
965192
  for (const [k5, v9] of Object.entries(raw)) {
965153
- if (THEME_ELIGIBLE_KEYS2.has(k5)) {
965193
+ if (docs_yml_exports.THEME_ELIGIBLE_YAML_KEYS.has(k5)) {
965154
965194
  themeConfig[k5] = v9;
965155
965195
  }
965156
965196
  }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.37.4",
2
+ "version": "5.37.5",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",