@fern-api/fern-api-dev 3.63.0 → 3.64.0

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 +593 -559
  2. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -1426227,7 +1426227,7 @@ var AccessTokenPosthogManager = class {
1426227
1426227
  properties: {
1426228
1426228
  ...event,
1426229
1426229
  ...event.properties,
1426230
- version: "3.63.0",
1426230
+ version: "3.64.0",
1426231
1426231
  usingAccessToken: true
1426232
1426232
  }
1426233
1426233
  });
@@ -1426326,7 +1426326,7 @@ var UserPosthogManager = class {
1426326
1426326
  distinctId: this.userId ?? await this.getPersistedDistinctId(),
1426327
1426327
  event: "CLI",
1426328
1426328
  properties: {
1426329
- version: "3.63.0",
1426329
+ version: "3.64.0",
1426330
1426330
  ...event,
1426331
1426331
  ...event.properties,
1426332
1426332
  usingAccessToken: false,
@@ -1452279,56 +1452279,149 @@ ${description}`);
1452279
1452279
  }
1452280
1452280
 
1452281
1452281
  // ../cli-v2/lib/commands/auth/login/command.js
1452282
+ var LoginCommand = class {
1452283
+ async handle(context2, args) {
1452284
+ const useDeviceCodeFlow = args["device-code"];
1452285
+ if (!useDeviceCodeFlow) {
1452286
+ context2.stdout.info("\u{1F33F} Welcome to Fern!");
1452287
+ context2.stdout.info("");
1452288
+ context2.stdout.info("Opening browser to log in to Fern...");
1452289
+ context2.stdout.info(source_default.dim(" If the browser doesn't open, try: fern auth login --device-code"));
1452290
+ }
1452291
+ const taskContext = new TaskContextAdapter({ context: context2, logLevel: LogLevel2.Info });
1452292
+ const tokenResponse = await getTokenFromAuth0(taskContext, {
1452293
+ useDeviceCodeFlow,
1452294
+ forceReauth: true
1452295
+ });
1452296
+ await this.storeAndConfirmLogin(context2, tokenResponse);
1452297
+ }
1452298
+ async storeAndConfirmLogin(context2, tokenResponse) {
1452299
+ const { accessToken, idToken } = tokenResponse;
1452300
+ const payload = await verifyAndDecodeJwt(idToken);
1452301
+ if (payload == null) {
1452302
+ context2.stdout.error(`${Icons.error} Internal error; could not verify ID token`);
1452303
+ throw CliError.exit();
1452304
+ }
1452305
+ const email3 = payload.email;
1452306
+ if (email3 == null) {
1452307
+ context2.stdout.error(`${Icons.error} Internal error; ID token does not contain email claim`);
1452308
+ throw CliError.exit();
1452309
+ }
1452310
+ const { isNew, totalAccounts } = await context2.tokenService.login(email3, accessToken);
1452311
+ if (isNew) {
1452312
+ context2.stdout.info(`${Icons.success} Logged in as ${source_default.bold(email3)}`);
1452313
+ if (totalAccounts > 1) {
1452314
+ context2.stdout.info(source_default.dim(` Account added. You now have ${totalAccounts} accounts.`));
1452315
+ context2.stdout.info(source_default.dim(` Active account: ${email3}`));
1452316
+ } else {
1452317
+ context2.stdout.info(source_default.dim(" Account stored in ~/.fernrc"));
1452318
+ }
1452319
+ return;
1452320
+ }
1452321
+ context2.stdout.info(`${Icons.success} Logged in as ${source_default.bold(email3)}`);
1452322
+ }
1452323
+ };
1452282
1452324
  function addLoginCommand(cli) {
1452283
- command2(cli, "login", "Log in to Fern", handleLogin, (yargs) => yargs.option("device-code", {
1452325
+ const cmd = new LoginCommand();
1452326
+ command2(cli, "login", "Log in to Fern", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("device-code", {
1452284
1452327
  type: "boolean",
1452285
1452328
  default: false,
1452286
1452329
  description: "Use device code flow (for environments where browser cannot open automatically)"
1452287
1452330
  }).example("$0 auth login", "Log in via browser").example("$0 auth login --device-code", "Log in via device code"));
1452288
1452331
  }
1452289
- async function handleLogin(context2, args) {
1452290
- const useDeviceCodeFlow = args["device-code"];
1452291
- if (!useDeviceCodeFlow) {
1452292
- context2.stdout.info("\u{1F33F} Welcome to Fern!");
1452293
- context2.stdout.info("");
1452294
- context2.stdout.info("Opening browser to log in to Fern..."), context2.stdout.info(source_default.dim(" If the browser doesn't open, try: fern auth login --device-code"));
1452332
+
1452333
+ // ../cli-v2/lib/commands/auth/logout/command.js
1452334
+ var LogoutCommand = class {
1452335
+ async handle(context2, args) {
1452336
+ const accounts = await context2.tokenService.getAllAccountInfo();
1452337
+ if (accounts.length === 0) {
1452338
+ context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452339
+ context2.stdout.info("");
1452340
+ context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452341
+ return;
1452342
+ }
1452343
+ if (args.all) {
1452344
+ await this.handleLogoutAll(context2, accounts, args.force);
1452345
+ return;
1452346
+ }
1452347
+ if (args.user != null) {
1452348
+ await this.handleLogoutUser(context2, args.user);
1452349
+ return;
1452350
+ }
1452351
+ if (accounts.length === 1) {
1452352
+ const singleAccount = accounts[0];
1452353
+ if (singleAccount != null) {
1452354
+ await this.handleLogoutUser(context2, singleAccount.user);
1452355
+ }
1452356
+ return;
1452357
+ }
1452358
+ await this.handleLogoutInteractive(context2, accounts);
1452295
1452359
  }
1452296
- const taskContext = new TaskContextAdapter({ context: context2, logLevel: LogLevel2.Info });
1452297
- const tokenResponse = await getTokenFromAuth0(taskContext, {
1452298
- useDeviceCodeFlow,
1452299
- forceReauth: true
1452300
- });
1452301
- await storeAndConfirmLogin(context2, tokenResponse);
1452302
- }
1452303
- async function storeAndConfirmLogin(context2, tokenResponse) {
1452304
- const { accessToken, idToken } = tokenResponse;
1452305
- const payload = await verifyAndDecodeJwt(idToken);
1452306
- if (payload == null) {
1452307
- context2.stdout.error(`${Icons.error} Internal error; could not verify ID token`);
1452308
- throw CliError.exit();
1452360
+ async handleLogoutAll(context2, accounts, force) {
1452361
+ if (force) {
1452362
+ await context2.tokenService.logoutAll();
1452363
+ context2.stdout.info(`${Icons.success} Logged out of all accounts`);
1452364
+ return;
1452365
+ }
1452366
+ context2.stdout.warn(`${source_default.yellow("\u26A0")} This will log out of all ${accounts.length} accounts:`);
1452367
+ for (const account of accounts) {
1452368
+ const activeMarker = account.isActive ? source_default.dim(" (active)") : "";
1452369
+ context2.stdout.info(` - ${account.user}${activeMarker}`);
1452370
+ }
1452371
+ context2.stdout.info("");
1452372
+ if (!context2.isTTY) {
1452373
+ context2.stdout.error(`${Icons.error} Use --force to skip confirmation in non-interactive mode`);
1452374
+ throw CliError.exit();
1452375
+ }
1452376
+ const { confirmed } = await lib_default3.prompt([
1452377
+ {
1452378
+ type: "confirm",
1452379
+ name: "confirmed",
1452380
+ message: "Continue?",
1452381
+ default: false
1452382
+ }
1452383
+ ]);
1452384
+ if (!confirmed) {
1452385
+ context2.stdout.info("Cancelled.");
1452386
+ return;
1452387
+ }
1452388
+ await context2.tokenService.logoutAll();
1452389
+ context2.stdout.info(`${Icons.success} Logged out of all accounts`);
1452309
1452390
  }
1452310
- const email3 = payload.email;
1452311
- if (email3 == null) {
1452312
- context2.stdout.error(`${Icons.error} Internal error; ID token does not contain email claim`);
1452313
- throw CliError.exit();
1452391
+ async handleLogoutUser(context2, user) {
1452392
+ const { removed, newActive } = await context2.tokenService.logout(user);
1452393
+ if (!removed) {
1452394
+ context2.stdout.error(`${Icons.error} Account not found: ${user}`);
1452395
+ throw CliError.exit();
1452396
+ }
1452397
+ context2.stdout.info(`${Icons.success} Logged out of ${source_default.bold(user)}`);
1452398
+ if (newActive != null) {
1452399
+ context2.stdout.info(source_default.dim(` Switched active account to ${newActive}`));
1452400
+ }
1452314
1452401
  }
1452315
- const { isNew, totalAccounts } = await context2.tokenService.login(email3, accessToken);
1452316
- if (isNew) {
1452317
- context2.stdout.info(`${Icons.success} Logged in as ${source_default.bold(email3)}`);
1452318
- if (totalAccounts > 1) {
1452319
- context2.stdout.info(source_default.dim(` Account added. You now have ${totalAccounts} accounts.`));
1452320
- context2.stdout.info(source_default.dim(` Active account: ${email3}`));
1452321
- } else {
1452322
- context2.stdout.info(source_default.dim(" Account stored in ~/.fernrc"));
1452402
+ async handleLogoutInteractive(context2, accounts) {
1452403
+ if (!context2.isTTY) {
1452404
+ context2.stdout.error(`${Icons.error} Multiple accounts found. Use --user or --all in non-interactive mode.`);
1452405
+ throw CliError.exit();
1452323
1452406
  }
1452324
- return;
1452407
+ const choices = accounts.map((account) => ({
1452408
+ name: account.isActive ? `${account.user} ${source_default.dim("(active)")}` : account.user,
1452409
+ value: account.user
1452410
+ }));
1452411
+ const { selectedUser } = await lib_default3.prompt([
1452412
+ {
1452413
+ type: "list",
1452414
+ name: "selectedUser",
1452415
+ message: "Select account to log out:",
1452416
+ choices
1452417
+ }
1452418
+ ]);
1452419
+ await this.handleLogoutUser(context2, selectedUser);
1452325
1452420
  }
1452326
- context2.stdout.info(`${Icons.success} Logged in as ${source_default.bold(email3)}`);
1452327
- }
1452328
-
1452329
- // ../cli-v2/lib/commands/auth/logout/command.js
1452421
+ };
1452330
1452422
  function addLogoutCommand(cli) {
1452331
- command2(cli, "logout", "Log out of Fern", handleLogout, (yargs) => yargs.option("user", {
1452423
+ const cmd = new LogoutCommand();
1452424
+ command2(cli, "logout", "Log out of Fern", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("user", {
1452332
1452425
  type: "string",
1452333
1452426
  description: "Log out of a specific account"
1452334
1452427
  }).option("all", {
@@ -1452341,98 +1452434,110 @@ function addLogoutCommand(cli) {
1452341
1452434
  description: "Skip confirmation prompt"
1452342
1452435
  }));
1452343
1452436
  }
1452344
- async function handleLogout(context2, args) {
1452345
- const accounts = await context2.tokenService.getAllAccountInfo();
1452346
- if (accounts.length === 0) {
1452347
- context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452348
- context2.stdout.info("");
1452349
- context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452350
- return;
1452351
- }
1452352
- if (args.all) {
1452353
- await handleLogoutAll(context2, accounts, args.force);
1452354
- return;
1452355
- }
1452356
- if (args.user != null) {
1452357
- await handleLogoutUser(context2, args.user);
1452358
- return;
1452359
- }
1452360
- if (accounts.length === 1) {
1452361
- const singleAccount = accounts[0];
1452362
- if (singleAccount != null) {
1452363
- await handleLogoutUser(context2, singleAccount.user);
1452437
+
1452438
+ // ../cli-v2/lib/constants.js
1452439
+ var FERN_TOKEN_ENV_VAR2 = "FERN_TOKEN";
1452440
+
1452441
+ // ../cli-v2/lib/commands/auth/status/command.js
1452442
+ var StatusCommand = class {
1452443
+ async handle(context2, args) {
1452444
+ const envToken = await getAccessToken();
1452445
+ if (envToken != null) {
1452446
+ await this.displayEnvTokenStatus(context2, envToken.value, args);
1452447
+ return;
1452364
1452448
  }
1452365
- return;
1452366
- }
1452367
- await handleLogoutInteractive(context2, accounts);
1452368
- }
1452369
- async function handleLogoutAll(context2, accounts, force) {
1452370
- if (force) {
1452371
- await context2.tokenService.logoutAll();
1452372
- context2.stdout.info(`${Icons.success} Logged out of all accounts`);
1452373
- }
1452374
- context2.stdout.warn(`${source_default.yellow("\u26A0")} This will log out of all ${accounts.length} accounts:`);
1452375
- for (const account of accounts) {
1452376
- const activeMarker = account.isActive ? source_default.dim(" (active)") : "";
1452377
- context2.stdout.info(` - ${account.user}${activeMarker}`);
1452378
- }
1452379
- context2.stdout.info("");
1452380
- if (!context2.isTTY) {
1452381
- context2.stdout.error(`${Icons.error} Use --force to skip confirmation in non-interactive mode`);
1452382
- throw CliError.exit();
1452449
+ const accounts = await context2.tokenService.getAllAccountInfo();
1452450
+ if (accounts.length === 0) {
1452451
+ if (args.json) {
1452452
+ context2.stdout.info(JSON.stringify({ accounts: [], activeAccount: null }, null, 2));
1452453
+ } else {
1452454
+ context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452455
+ context2.stdout.info("");
1452456
+ context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452457
+ }
1452458
+ return;
1452459
+ }
1452460
+ if (args.json) {
1452461
+ await this.displayJsonStatus(context2, accounts);
1452462
+ return;
1452463
+ }
1452464
+ if (args.active) {
1452465
+ const activeAccount = accounts.find((a10) => a10.isActive);
1452466
+ if (activeAccount != null) {
1452467
+ await this.displaySingleAccountStatus(context2, activeAccount);
1452468
+ }
1452469
+ return;
1452470
+ }
1452471
+ if (accounts.length === 1) {
1452472
+ const singleAccount = accounts[0];
1452473
+ if (singleAccount != null) {
1452474
+ await this.displaySingleAccountStatus(context2, singleAccount);
1452475
+ }
1452476
+ return;
1452477
+ }
1452478
+ await this.displayMultiAccountStatus(context2, accounts);
1452383
1452479
  }
1452384
- const { confirmed } = await lib_default3.prompt([
1452385
- {
1452386
- type: "confirm",
1452387
- name: "confirmed",
1452388
- message: "Continue?",
1452389
- default: false
1452480
+ async displayEnvTokenStatus(context2, token, args) {
1452481
+ if (args.json) {
1452482
+ context2.stdout.info(JSON.stringify({
1452483
+ source: FERN_TOKEN_ENV_VAR2,
1452484
+ token: this.maskToken(token)
1452485
+ }, null, 2));
1452486
+ return;
1452390
1452487
  }
1452391
- ]);
1452392
- if (!confirmed) {
1452393
- context2.stdout.info("Cancelled.");
1452394
- return;
1452488
+ context2.stdout.info(source_default.bold(`Using ${FERN_TOKEN_ENV_VAR2} environment variable`));
1452489
+ context2.stdout.info("");
1452490
+ context2.stdout.info(source_default.dim(` The ${FERN_TOKEN_ENV_VAR2} environment variable overrides stored accounts.`));
1452491
+ context2.stdout.info(source_default.dim(` To use stored accounts, unset ${FERN_TOKEN_ENV_VAR2}.`));
1452492
+ context2.stdout.info("");
1452395
1452493
  }
1452396
- await context2.tokenService.logoutAll();
1452397
- context2.stdout.info(`${Icons.success} Logged out of all accounts`);
1452398
- }
1452399
- async function handleLogoutUser(context2, user) {
1452400
- const { removed, newActive } = await context2.tokenService.logout(user);
1452401
- if (!removed) {
1452402
- context2.stdout.error(`${Icons.error} Account not found: ${user}`);
1452403
- throw CliError.exit();
1452494
+ async displaySingleAccountStatus(context2, account) {
1452495
+ context2.stdout.info(source_default.bold("Logged in to Fern"));
1452496
+ context2.stdout.info("");
1452497
+ context2.stdout.info(` Account: ${account.user}`);
1452498
+ const statusText = account.tokenInfo?.isExpired === true ? source_default.yellow("Expired") : source_default.green("Active");
1452499
+ context2.stdout.info(` Status: ${statusText}`);
1452500
+ if (account.tokenInfo != null) {
1452501
+ context2.stdout.info(` Expires: ${account.tokenInfo.expiresIn}`);
1452502
+ }
1452404
1452503
  }
1452405
- context2.stdout.info(`${Icons.success} Logged out of ${source_default.bold(user)}`);
1452406
- if (newActive != null) {
1452407
- context2.stdout.info(source_default.dim(` Switched active account to ${newActive}`));
1452504
+ async displayMultiAccountStatus(context2, accounts) {
1452505
+ context2.stdout.info(source_default.bold("Logged in to Fern"));
1452506
+ context2.stdout.info("");
1452507
+ const maxNameWidth = Math.max(...accounts.map((a10) => a10.user.length));
1452508
+ for (const account of accounts) {
1452509
+ const prefix2 = account.isActive ? source_default.cyan(">") : " ";
1452510
+ const statusText = account.tokenInfo?.isExpired === true ? source_default.yellow("Expired") : source_default.green("Active");
1452511
+ const expiryText = account.tokenInfo != null ? `expires ${account.tokenInfo.expiresIn}` : "";
1452512
+ const expiredHint = account.tokenInfo?.isExpired === true ? source_default.dim(" run: fern auth login") : "";
1452513
+ const paddedName = account.user.padEnd(maxNameWidth);
1452514
+ context2.stdout.info(` ${prefix2} ${paddedName} ${statusText} ${expiryText}${expiredHint}`);
1452515
+ }
1452408
1452516
  }
1452409
- }
1452410
- async function handleLogoutInteractive(context2, accounts) {
1452411
- if (!context2.isTTY) {
1452412
- context2.stdout.error(`${Icons.error} Multiple accounts found. Use --user or --all in non-interactive mode.`);
1452413
- throw CliError.exit();
1452517
+ async displayJsonStatus(context2, accounts) {
1452518
+ const activeAccount = accounts.find((a10) => a10.isActive);
1452519
+ const output2 = {
1452520
+ accounts: accounts.map((account) => ({
1452521
+ user: account.user,
1452522
+ active: account.isActive,
1452523
+ status: account.tokenInfo?.isExpired === true ? "expired" : "valid",
1452524
+ expiresAt: account.tokenInfo?.expiresAt?.toISOString() ?? null,
1452525
+ token: account.tokenInfo != null ? this.maskToken(account.tokenInfo.token) : null
1452526
+ })),
1452527
+ activeAccount: activeAccount?.user ?? null
1452528
+ };
1452529
+ context2.stdout.info(JSON.stringify(output2, null, 2));
1452414
1452530
  }
1452415
- const choices = accounts.map((account) => ({
1452416
- name: account.isActive ? `${account.user} ${source_default.dim("(active)")}` : account.user,
1452417
- value: account.user
1452418
- }));
1452419
- const { selectedUser } = await lib_default3.prompt([
1452420
- {
1452421
- type: "list",
1452422
- name: "selectedUser",
1452423
- message: "Select account to log out:",
1452424
- choices
1452531
+ maskToken(token) {
1452532
+ if (token.length <= 10) {
1452533
+ return "***";
1452425
1452534
  }
1452426
- ]);
1452427
- await handleLogoutUser(context2, selectedUser);
1452428
- }
1452429
-
1452430
- // ../cli-v2/lib/constants.js
1452431
- var FERN_TOKEN_ENV_VAR2 = "FERN_TOKEN";
1452432
-
1452433
- // ../cli-v2/lib/commands/auth/status/command.js
1452535
+ return `${token.slice(0, 4)}...${token.slice(-4)}`;
1452536
+ }
1452537
+ };
1452434
1452538
  function addStatusCommand(cli) {
1452435
- command2(cli, "status", "Show authentication status", handleStatus, (yargs) => yargs.option("json", {
1452539
+ const cmd = new StatusCommand();
1452540
+ command2(cli, "status", "Show authentication status", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("json", {
1452436
1452541
  type: "boolean",
1452437
1452542
  default: false,
1452438
1452543
  description: "Output as JSON"
@@ -1452442,252 +1452547,167 @@ function addStatusCommand(cli) {
1452442
1452547
  description: "Show active account only"
1452443
1452548
  }));
1452444
1452549
  }
1452445
- async function handleStatus(context2, args) {
1452446
- const envToken = await getAccessToken();
1452447
- if (envToken != null) {
1452448
- await displayEnvTokenStatus(context2, envToken.value, args);
1452449
- return;
1452450
- }
1452451
- const accounts = await context2.tokenService.getAllAccountInfo();
1452452
- if (accounts.length === 0) {
1452453
- if (args.json) {
1452454
- context2.stdout.info(JSON.stringify({ accounts: [], activeAccount: null }, null, 2));
1452455
- } else {
1452550
+
1452551
+ // ../cli-v2/lib/commands/auth/switch/command.js
1452552
+ var SwitchCommand = class {
1452553
+ async handle(context2, args) {
1452554
+ const accounts = await context2.tokenService.getAllAccountInfo();
1452555
+ if (accounts.length === 0) {
1452456
1452556
  context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452457
1452557
  context2.stdout.info("");
1452458
1452558
  context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452559
+ throw CliError.exit();
1452459
1452560
  }
1452460
- return;
1452461
- }
1452462
- if (args.json) {
1452463
- await displayJsonStatus(context2, accounts);
1452464
- return;
1452465
- }
1452466
- if (args.active) {
1452467
- const activeAccount = accounts.find((a10) => a10.isActive);
1452468
- if (activeAccount != null) {
1452469
- await displaySingleAccountStatus(context2, activeAccount);
1452561
+ if (accounts.length === 1) {
1452562
+ const account = accounts[0];
1452563
+ if (account == null) {
1452564
+ context2.stdout.error(`${Icons.error} Internal error; no accounts found`);
1452565
+ throw CliError.exit();
1452566
+ }
1452567
+ context2.stdout.warn(`${source_default.yellow("\u26A0")} You only have one account logged in: ${source_default.bold(account.user)}`);
1452568
+ context2.stdout.info("");
1452569
+ context2.stdout.info(source_default.dim(" To add another account, run: fern auth login"));
1452570
+ return;
1452470
1452571
  }
1452471
- return;
1452472
- }
1452473
- if (accounts.length === 1) {
1452474
- const singleAccount = accounts[0];
1452475
- if (singleAccount != null) {
1452476
- await displaySingleAccountStatus(context2, singleAccount);
1452572
+ if (args.user != null) {
1452573
+ await this.switchToUser(context2, args.user);
1452574
+ return;
1452477
1452575
  }
1452478
- return;
1452479
- }
1452480
- await displayMultiAccountStatus(context2, accounts);
1452481
- }
1452482
- async function displayEnvTokenStatus(context2, token, args) {
1452483
- if (args.json) {
1452484
- context2.stdout.info(JSON.stringify({
1452485
- source: FERN_TOKEN_ENV_VAR2,
1452486
- token: maskToken(token)
1452487
- }, null, 2));
1452488
- return;
1452489
- }
1452490
- context2.stdout.info(source_default.bold(`Using ${FERN_TOKEN_ENV_VAR2} environment variable`));
1452491
- context2.stdout.info("");
1452492
- context2.stdout.info(source_default.dim(` The ${FERN_TOKEN_ENV_VAR2} environment variable overrides stored accounts.`));
1452493
- context2.stdout.info(source_default.dim(` To use stored accounts, unset ${FERN_TOKEN_ENV_VAR2}.`));
1452494
- context2.stdout.info("");
1452495
- }
1452496
- async function displaySingleAccountStatus(context2, account) {
1452497
- context2.stdout.info(source_default.bold("Logged in to Fern"));
1452498
- context2.stdout.info("");
1452499
- context2.stdout.info(` Account: ${account.user}`);
1452500
- const statusText = account.tokenInfo?.isExpired === true ? source_default.yellow("Expired") : source_default.green("Active");
1452501
- context2.stdout.info(` Status: ${statusText}`);
1452502
- if (account.tokenInfo != null) {
1452503
- context2.stdout.info(` Expires: ${account.tokenInfo.expiresIn}`);
1452504
- }
1452505
- }
1452506
- async function displayMultiAccountStatus(context2, accounts) {
1452507
- context2.stdout.info(source_default.bold("Logged in to Fern"));
1452508
- context2.stdout.info("");
1452509
- const maxNameWidth = Math.max(...accounts.map((a10) => a10.user.length));
1452510
- for (const account of accounts) {
1452511
- const prefix2 = account.isActive ? source_default.cyan(">") : " ";
1452512
- const statusText = account.tokenInfo?.isExpired === true ? source_default.yellow("Expired") : source_default.green("Active");
1452513
- const expiryText = account.tokenInfo != null ? `expires ${account.tokenInfo.expiresIn}` : "";
1452514
- const expiredHint = account.tokenInfo?.isExpired === true ? source_default.dim(" run: fern auth login") : "";
1452515
- const paddedName = account.user.padEnd(maxNameWidth);
1452516
- context2.stdout.info(` ${prefix2} ${paddedName} ${statusText} ${expiryText}${expiredHint}`);
1452517
- }
1452518
- }
1452519
- async function displayJsonStatus(context2, accounts) {
1452520
- const activeAccount = accounts.find((a10) => a10.isActive);
1452521
- const output2 = {
1452522
- accounts: accounts.map((account) => ({
1452523
- user: account.user,
1452524
- active: account.isActive,
1452525
- status: account.tokenInfo?.isExpired === true ? "expired" : "valid",
1452526
- expiresAt: account.tokenInfo?.expiresAt?.toISOString() ?? null,
1452527
- token: account.tokenInfo != null ? maskToken(account.tokenInfo.token) : null
1452528
- })),
1452529
- activeAccount: activeAccount?.user ?? null
1452530
- };
1452531
- context2.stdout.info(JSON.stringify(output2, null, 2));
1452532
- }
1452533
- function maskToken(token) {
1452534
- if (token.length <= 10) {
1452535
- return "***";
1452536
- }
1452537
- return `${token.slice(0, 4)}...${token.slice(-4)}`;
1452538
- }
1452539
-
1452540
- // ../cli-v2/lib/commands/auth/switch/command.js
1452541
- function addSwitchCommand(cli) {
1452542
- command2(cli, "switch", "Switch active account", handleSwitch, (yargs) => yargs.option("user", {
1452543
- type: "string",
1452544
- description: "Switch to specific account"
1452545
- }));
1452546
- }
1452547
- async function handleSwitch(context2, args) {
1452548
- const accounts = await context2.tokenService.getAllAccountInfo();
1452549
- if (accounts.length === 0) {
1452550
- context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452551
- context2.stdout.info("");
1452552
- context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452553
- throw CliError.exit();
1452576
+ if (accounts.length === 2) {
1452577
+ const otherAccount = accounts.find((a10) => !a10.isActive);
1452578
+ if (otherAccount != null) {
1452579
+ await this.switchToUser(context2, otherAccount.user);
1452580
+ }
1452581
+ return;
1452582
+ }
1452583
+ await this.handleInteractiveSwitch(context2, accounts);
1452554
1452584
  }
1452555
- if (accounts.length === 1) {
1452556
- const account = accounts[0];
1452557
- if (account == null) {
1452558
- context2.stdout.error(`${Icons.error} Internal error; no accounts found`);
1452585
+ async handleInteractiveSwitch(context2, accounts) {
1452586
+ if (!context2.isTTY) {
1452587
+ context2.stdout.error(`${Icons.error} Use --user to specify account in non-interactive mode`);
1452559
1452588
  throw CliError.exit();
1452560
1452589
  }
1452561
- context2.stdout.warn(`${source_default.yellow("\u26A0")} You only have one account logged in: ${source_default.bold(account.user)}`);
1452562
- context2.stdout.info("");
1452563
- context2.stdout.info(source_default.dim(" To add another account, run: fern auth login"));
1452564
- return;
1452565
- }
1452566
- if (args.user != null) {
1452567
- await switchToUser(context2, args.user);
1452568
- return;
1452590
+ const choices = accounts.map((account) => ({
1452591
+ name: account.isActive ? `${account.user} ${source_default.dim("(current)")}` : account.user,
1452592
+ value: account.user,
1452593
+ disabled: account.isActive ? "(current)" : false
1452594
+ }));
1452595
+ const { selectedUser } = await lib_default3.prompt([
1452596
+ {
1452597
+ type: "list",
1452598
+ name: "selectedUser",
1452599
+ message: "Select account:",
1452600
+ choices
1452601
+ }
1452602
+ ]);
1452603
+ await this.switchToUser(context2, selectedUser);
1452569
1452604
  }
1452570
- if (accounts.length === 2) {
1452571
- const otherAccount = accounts.find((a10) => !a10.isActive);
1452572
- if (otherAccount != null) {
1452573
- await switchToUser(context2, otherAccount.user);
1452605
+ async switchToUser(context2, user) {
1452606
+ const success2 = await context2.tokenService.switchAccount(user);
1452607
+ if (!success2) {
1452608
+ context2.stdout.error(`${Icons.error} Account not found: ${user}`);
1452609
+ throw CliError.exit();
1452574
1452610
  }
1452575
- return;
1452576
- }
1452577
- await handleInteractiveSwitch(context2, accounts);
1452578
- }
1452579
- async function switchToUser(context2, user) {
1452580
- const success2 = await context2.tokenService.switchAccount(user);
1452581
- if (!success2) {
1452582
- context2.stdout.error(`${Icons.error} Account not found: ${user}`);
1452583
- throw CliError.exit();
1452611
+ context2.stdout.info(`${Icons.success} Switched to ${source_default.bold(user)}`);
1452584
1452612
  }
1452585
- context2.stdout.info(`${Icons.success} Switched to ${source_default.bold(user)}`);
1452586
- }
1452587
- async function handleInteractiveSwitch(context2, accounts) {
1452588
- if (!context2.isTTY) {
1452589
- context2.stdout.error(`${Icons.error} Use --user to specify account in non-interactive mode`);
1452590
- throw CliError.exit();
1452591
- }
1452592
- const choices = accounts.map((account) => ({
1452593
- name: account.isActive ? `${account.user} ${source_default.dim("(current)")}` : account.user,
1452594
- value: account.user,
1452595
- disabled: account.isActive ? "(current)" : false
1452613
+ };
1452614
+ function addSwitchCommand(cli) {
1452615
+ const cmd = new SwitchCommand();
1452616
+ command2(cli, "switch", "Switch active account", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("user", {
1452617
+ type: "string",
1452618
+ description: "Switch to specific account"
1452596
1452619
  }));
1452597
- const { selectedUser } = await lib_default3.prompt([
1452598
- {
1452599
- type: "list",
1452600
- name: "selectedUser",
1452601
- message: "Select account:",
1452602
- choices
1452603
- }
1452604
- ]);
1452605
- await switchToUser(context2, selectedUser);
1452606
1452620
  }
1452607
1452621
 
1452608
1452622
  // ../cli-v2/lib/commands/auth/token/command.js
1452609
- function addTokenCommand(cli) {
1452610
- command2(cli, "token", "Generate an organization access token (FERN_TOKEN)", handleToken, (yargs) => yargs.option("org", {
1452611
- type: "string",
1452612
- description: "Organization to generate token for (defaults to organization in fern.yml)"
1452613
- }).example("$0 auth token", "Generate token for workspace organization").example("$0 auth token --org acme", "Generate token for specific organization").example("export FERN_TOKEN=$($0 auth token)", "Export token to variable"));
1452614
- }
1452615
- async function handleToken(context2, args) {
1452616
- const orgId = await resolveOrganization({ context: context2, args });
1452617
- const token = await context2.getTokenOrPrompt();
1452618
- if (token.type === "user") {
1452619
- await createOrganizationIfDoesNotExist({
1452620
- organization: orgId,
1452621
- token,
1452622
- context: new TaskContextAdapter({ context: context2 })
1452623
+ var TokenCommand = class {
1452624
+ async handle(context2, args) {
1452625
+ const orgId = await this.resolveOrganization(context2, args);
1452626
+ const token = await context2.getTokenOrPrompt();
1452627
+ if (token.type === "user") {
1452628
+ await createOrganizationIfDoesNotExist({
1452629
+ organization: orgId,
1452630
+ token,
1452631
+ context: new TaskContextAdapter({ context: context2 })
1452632
+ });
1452633
+ }
1452634
+ const venus = createVenusService({ token: token.value });
1452635
+ const response = await venus.registry.generateRegistryTokens({
1452636
+ organizationId: api_exports4.OrganizationId(orgId)
1452623
1452637
  });
1452624
- }
1452625
- const venus = createVenusService({ token: token.value });
1452626
- const response = await venus.registry.generateRegistryTokens({
1452627
- organizationId: api_exports4.OrganizationId(orgId)
1452628
- });
1452629
- if (response.ok) {
1452630
- process.stdout.write(response.body.npm.token);
1452631
- return;
1452632
- }
1452633
- response.error._visit({
1452634
- organizationNotFoundError: () => {
1452635
- process.stderr.write(`${Icons.error} Organization "${orgId}" was not found.
1452638
+ if (response.ok) {
1452639
+ process.stdout.write(response.body.npm.token);
1452640
+ return;
1452641
+ }
1452642
+ response.error._visit({
1452643
+ organizationNotFoundError: () => {
1452644
+ process.stderr.write(`${Icons.error} Organization "${orgId}" was not found.
1452636
1452645
  `);
1452637
- throw CliError.exit();
1452638
- },
1452639
- unauthorizedError: () => {
1452640
- process.stderr.write(`${Icons.error} You do not have access to organization "${orgId}".
1452646
+ throw CliError.exit();
1452647
+ },
1452648
+ unauthorizedError: () => {
1452649
+ process.stderr.write(`${Icons.error} You do not have access to organization "${orgId}".
1452641
1452650
  `);
1452642
- throw CliError.exit();
1452643
- },
1452644
- _other: () => {
1452645
- process.stderr.write(`${Icons.error} Failed to generate token.
1452651
+ throw CliError.exit();
1452652
+ },
1452653
+ _other: () => {
1452654
+ process.stderr.write(`${Icons.error} Failed to generate token.
1452646
1452655
 
1452647
1452656
  Please contact support@buildwithfern.com for assistance.
1452648
1452657
  `);
1452649
- throw CliError.exit();
1452650
- }
1452651
- });
1452652
- }
1452653
- async function resolveOrganization({ context: context2, args }) {
1452654
- if (args.org != null) {
1452655
- return args.org;
1452658
+ throw CliError.exit();
1452659
+ }
1452660
+ });
1452656
1452661
  }
1452657
- try {
1452658
- const workspace = await context2.loadWorkspaceOrThrow();
1452659
- return workspace.org;
1452660
- } catch {
1452661
- process.stderr.write(`${Icons.error} No organization specified.
1452662
+ async resolveOrganization(context2, args) {
1452663
+ if (args.org != null) {
1452664
+ return args.org;
1452665
+ }
1452666
+ try {
1452667
+ const workspace = await context2.loadWorkspaceOrThrow();
1452668
+ return workspace.org;
1452669
+ } catch {
1452670
+ process.stderr.write(`${Icons.error} No organization specified.
1452662
1452671
 
1452663
1452672
  Run fern init or specify an organization with --org, then run this command again.
1452664
1452673
  `);
1452665
- throw CliError.exit();
1452674
+ throw CliError.exit();
1452675
+ }
1452666
1452676
  }
1452677
+ };
1452678
+ function addTokenCommand(cli) {
1452679
+ const cmd = new TokenCommand();
1452680
+ command2(cli, "token", "Generate an organization access token (FERN_TOKEN)", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("org", {
1452681
+ type: "string",
1452682
+ description: "Organization to generate token for (defaults to organization in fern.yml)"
1452683
+ }).example("$0 auth token", "Generate token for workspace organization").example("$0 auth token --org acme", "Generate token for specific organization").example("export FERN_TOKEN=$($0 auth token)", "Export token to variable"));
1452667
1452684
  }
1452668
1452685
 
1452669
1452686
  // ../cli-v2/lib/commands/auth/whoami/command.js
1452687
+ var WhoamiCommand = class {
1452688
+ async handle(context2, args) {
1452689
+ const activeAccount = await context2.tokenService.getActiveAccountInfo();
1452690
+ if (activeAccount == null) {
1452691
+ context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452692
+ context2.stdout.info("");
1452693
+ context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452694
+ throw CliError.exit();
1452695
+ }
1452696
+ if (args.json) {
1452697
+ context2.stdout.info(JSON.stringify({ email: activeAccount.user }, null, 2));
1452698
+ return;
1452699
+ }
1452700
+ context2.stdout.info(source_default.bold(activeAccount.user));
1452701
+ }
1452702
+ };
1452670
1452703
  function addWhoamiCommand(cli) {
1452671
- command2(cli, "whoami", "Print the current user", handleWhoami, (yargs) => yargs.option("json", {
1452704
+ const cmd = new WhoamiCommand();
1452705
+ command2(cli, "whoami", "Print the current user", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("json", {
1452672
1452706
  type: "boolean",
1452673
1452707
  default: false,
1452674
1452708
  description: "Output as JSON"
1452675
1452709
  }));
1452676
1452710
  }
1452677
- async function handleWhoami(context2, args) {
1452678
- const activeAccount = await context2.tokenService.getActiveAccountInfo();
1452679
- if (activeAccount == null) {
1452680
- context2.stdout.warn(`${source_default.yellow("\u26A0")} You are not logged in to Fern.`);
1452681
- context2.stdout.info("");
1452682
- context2.stdout.info(source_default.dim(" To log in, run: fern auth login"));
1452683
- throw CliError.exit();
1452684
- }
1452685
- if (args.json) {
1452686
- context2.stdout.info(JSON.stringify({ email: activeAccount.user }, null, 2));
1452687
- return;
1452688
- }
1452689
- context2.stdout.info(source_default.bold(activeAccount.user));
1452690
- }
1452691
1452711
 
1452692
1452712
  // ../cli-v2/lib/commands/auth/command.js
1452693
1452713
  function addAuthCommand(cli) {
@@ -1562459,8 +1562479,37 @@ var ApiChecker = class {
1562459
1562479
  };
1562460
1562480
 
1562461
1562481
  // ../cli-v2/lib/commands/check/command.js
1562482
+ var CheckCommand = class {
1562483
+ async handle(context2, args) {
1562484
+ const workspace = await context2.loadWorkspaceOrThrow();
1562485
+ this.validateArgs(args, workspace);
1562486
+ const checker = new ApiChecker({
1562487
+ context: context2,
1562488
+ cliVersion: workspace.cliVersion
1562489
+ });
1562490
+ const checkResult = await checker.check({
1562491
+ workspace,
1562492
+ apiNames: args.api != null ? [args.api] : void 0,
1562493
+ strict: args.strict
1562494
+ });
1562495
+ const hasErrors = checkResult.invalidApis.size > 0;
1562496
+ const hasWarnings = checkResult.warningCount > 0;
1562497
+ if (hasErrors || args.strict && hasWarnings) {
1562498
+ throw CliError.exit();
1562499
+ }
1562500
+ }
1562501
+ validateArgs(args, workspace) {
1562502
+ if (args.api != null && workspace.apis[args.api] == null) {
1562503
+ const availableApis = Object.keys(workspace.apis).join(", ");
1562504
+ throw new CliError({
1562505
+ message: `API '${args.api}' not found. Available APIs: ${availableApis}`
1562506
+ });
1562507
+ }
1562508
+ }
1562509
+ };
1562462
1562510
  function addCheckCommand(cli) {
1562463
- command2(cli, "check", "Validate your API, docs, and SDK configuration", handleCheck, (yargs) => yargs.option("api", {
1562511
+ const cmd = new CheckCommand();
1562512
+ command2(cli, "check", "Validate your API, docs, and SDK configuration", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("api", {
1562464
1562513
  type: "string",
1562465
1562514
  description: "Validate a specific API"
1562466
1562515
  }).option("strict", {
@@ -1562469,32 +1562518,6 @@ function addCheckCommand(cli) {
1562469
1562518
  default: false
1562470
1562519
  }));
1562471
1562520
  }
1562472
- async function handleCheck(context2, args) {
1562473
- const workspace = await context2.loadWorkspaceOrThrow();
1562474
- validateArgs({ args, workspace });
1562475
- const checker = new ApiChecker({
1562476
- context: context2,
1562477
- cliVersion: workspace.cliVersion
1562478
- });
1562479
- const checkResult = await checker.check({
1562480
- workspace,
1562481
- apiNames: args.api != null ? [args.api] : void 0,
1562482
- strict: args.strict
1562483
- });
1562484
- const hasErrors = checkResult.invalidApis.size > 0;
1562485
- const hasWarnings = checkResult.warningCount > 0;
1562486
- if (hasErrors || args.strict && hasWarnings) {
1562487
- throw CliError.exit();
1562488
- }
1562489
- }
1562490
- function validateArgs({ args, workspace }) {
1562491
- if (args.api != null && workspace.apis[args.api] == null) {
1562492
- const availableApis = Object.keys(workspace.apis).join(", ");
1562493
- throw new CliError({
1562494
- message: `API '${args.api}' not found. Available APIs: ${availableApis}`
1562495
- });
1562496
- }
1562497
- }
1562498
1562521
 
1562499
1562522
  // ../cli-v2/lib/migrator/Migrator.js
1562500
1562523
  var import_promises44 = require("fs/promises");
@@ -1563811,47 +1563834,50 @@ var Migrator = class {
1563811
1563834
  };
1563812
1563835
 
1563813
1563836
  // ../cli-v2/lib/commands/config/migrate/command.js
1563837
+ var MigrateCommand = class {
1563838
+ async handle(context2, args) {
1563839
+ const migrator = new Migrator({
1563840
+ cwd: context2.cwd,
1563841
+ logger: context2.stdout,
1563842
+ deleteOriginals: args.delete
1563843
+ });
1563844
+ const result = await migrator.migrate();
1563845
+ for (const warning of result.warnings) {
1563846
+ switch (warning.type) {
1563847
+ case "deprecated":
1563848
+ context2.stdout.warn(`Deprecated: ${warning.message}`);
1563849
+ break;
1563850
+ case "unsupported":
1563851
+ context2.stdout.warn(`Unsupported: ${warning.message}`);
1563852
+ break;
1563853
+ case "conflict":
1563854
+ context2.stderr.error(`Error: ${warning.message}`);
1563855
+ break;
1563856
+ case "info":
1563857
+ context2.stdout.info(warning.message);
1563858
+ break;
1563859
+ }
1563860
+ if (warning.suggestion != null) {
1563861
+ context2.stdout.info(` Suggestion: ${warning.suggestion}`);
1563862
+ }
1563863
+ }
1563864
+ if (result.success) {
1563865
+ if (result.outputPath != null) {
1563866
+ context2.stdout.debug(`Created: ${result.outputPath}`);
1563867
+ }
1563868
+ return;
1563869
+ }
1563870
+ throw new CliError({ message: "Migration failed" });
1563871
+ }
1563872
+ };
1563814
1563873
  function addMigrateCommand(cli) {
1563815
- command2(cli, "migrate", "Migrate legacy configuration files to fern.yml", handleMigrate, (yargs) => yargs.option("delete", {
1563874
+ const cmd = new MigrateCommand();
1563875
+ command2(cli, "migrate", "Migrate legacy configuration files to fern.yml", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("delete", {
1563816
1563876
  type: "boolean",
1563817
1563877
  description: "Keep original files after migration",
1563818
1563878
  default: true
1563819
1563879
  }));
1563820
1563880
  }
1563821
- async function handleMigrate(context2, args) {
1563822
- const migrator = new Migrator({
1563823
- cwd: context2.cwd,
1563824
- logger: context2.stdout,
1563825
- deleteOriginals: args.delete
1563826
- });
1563827
- const result = await migrator.migrate();
1563828
- for (const warning of result.warnings) {
1563829
- switch (warning.type) {
1563830
- case "deprecated":
1563831
- context2.stdout.warn(`Deprecated: ${warning.message}`);
1563832
- break;
1563833
- case "unsupported":
1563834
- context2.stdout.warn(`Unsupported: ${warning.message}`);
1563835
- break;
1563836
- case "conflict":
1563837
- context2.stderr.error(`Error: ${warning.message}`);
1563838
- break;
1563839
- case "info":
1563840
- context2.stdout.info(warning.message);
1563841
- break;
1563842
- }
1563843
- if (warning.suggestion != null) {
1563844
- context2.stdout.info(` Suggestion: ${warning.suggestion}`);
1563845
- }
1563846
- }
1563847
- if (result.success) {
1563848
- if (result.outputPath != null) {
1563849
- context2.stdout.debug(`Created: ${result.outputPath}`);
1563850
- }
1563851
- return;
1563852
- }
1563853
- throw new CliError({ message: "Migration failed" });
1563854
- }
1563855
1563881
 
1563856
1563882
  // ../cli-v2/lib/commands/config/command.js
1563857
1563883
  function addConfigCommand(cli) {
@@ -1617448,6 +1617474,7 @@ var LocalTaskHandler = class {
1617448
1617474
  await this.copyGeneratedFilesToDirectory(this.absolutePathToLocalOutput);
1617449
1617475
  await this.runGitCommand(["add", "."], this.absolutePathToLocalOutput);
1617450
1617476
  await this.runGitCommand(["reset", "--", ...fernIgnorePaths], this.absolutePathToLocalOutput);
1617477
+ await this.runGitCommand(["clean", "-fd", "--", ...fernIgnorePaths], this.absolutePathToLocalOutput);
1617451
1617478
  await this.runGitCommand(["restore", "."], this.absolutePathToLocalOutput);
1617452
1617479
  }
1617453
1617480
  async copyGeneratedFilesWithFernIgnoreInTempRepo() {
@@ -1617467,6 +1617494,7 @@ var LocalTaskHandler = class {
1617467
1617494
  await this.copyGeneratedFilesToDirectory(tmpOutputResolutionDir);
1617468
1617495
  await this.runGitCommand(["add", "."], tmpOutputResolutionDir);
1617469
1617496
  await this.runGitCommand(["reset", "--", ...fernIgnorePaths], tmpOutputResolutionDir);
1617497
+ await this.runGitCommand(["clean", "-fd", "--", ...fernIgnorePaths], tmpOutputResolutionDir);
1617470
1617498
  await this.runGitCommand(["restore", "."], tmpOutputResolutionDir);
1617471
1617499
  await (0, import_promises55.rm)(join4(tmpOutputResolutionDir, RelativeFilePath2.of(".git")), { recursive: true });
1617472
1617500
  await (0, import_promises55.rm)(this.absolutePathToLocalOutput, { recursive: true });
@@ -1681062,8 +1681090,175 @@ ${source_default.dim(`Logs written to: ${logFilePath}`)}
1681062
1681090
  };
1681063
1681091
 
1681064
1681092
  // ../cli-v2/lib/commands/sdk/generate/command.js
1681093
+ var GenerateCommand = class {
1681094
+ async handle(context2, args) {
1681095
+ this.validateArgs(args);
1681096
+ const workspace = await context2.loadWorkspaceOrThrow();
1681097
+ if (workspace.sdks == null) {
1681098
+ throw new Error("No SDKs configured in fern.yml");
1681099
+ }
1681100
+ const targets2 = this.getTargets({
1681101
+ workspace,
1681102
+ groupName: args.group ?? workspace.sdks.defaultGroup,
1681103
+ targetName: args.target
1681104
+ });
1681105
+ const apisToCheck = [...new Set(targets2.map((t2) => t2.api))];
1681106
+ const checker = new ApiChecker({
1681107
+ context: context2,
1681108
+ cliVersion: workspace.cliVersion
1681109
+ });
1681110
+ const checkResult = await checker.check({
1681111
+ workspace,
1681112
+ apiNames: apisToCheck
1681113
+ });
1681114
+ const validTargets = targets2.filter((t2) => checkResult.validApis.has(t2.api));
1681115
+ if (validTargets.length === 0) {
1681116
+ throw CliError.exit();
1681117
+ }
1681118
+ const pipeline5 = new GeneratorPipeline({
1681119
+ context: context2,
1681120
+ cliVersion: workspace.cliVersion
1681121
+ });
1681122
+ const token = args.local ? void 0 : await context2.getTokenOrPrompt();
1681123
+ const runtime = args.local ? "local" : "remote";
1681124
+ const taskGroup = new TaskGroup({ context: context2 });
1681125
+ const skippedTargets = targets2.filter((t2) => checkResult.invalidApis.has(t2.api));
1681126
+ for (const target of skippedTargets) {
1681127
+ taskGroup.addTask({
1681128
+ id: target.name,
1681129
+ name: target.name,
1681130
+ status: "skipped",
1681131
+ skipReason: `API '${target.api}' has errors`
1681132
+ });
1681133
+ }
1681134
+ for (const target of validTargets) {
1681135
+ taskGroup.addTask({
1681136
+ id: target.name,
1681137
+ name: target.name
1681138
+ });
1681139
+ }
1681140
+ await taskGroup.start({
1681141
+ title: "Generating SDKs",
1681142
+ subtitle: `org: ${workspace.sdks.org}`
1681143
+ });
1681144
+ await Promise.all(validTargets.map(async (target) => {
1681145
+ const apiDefinition = workspace.apis[target.api];
1681146
+ if (apiDefinition == null) {
1681147
+ const message = `API '${target.api}' not found in workspace`;
1681148
+ taskGroup.updateTask({
1681149
+ id: target.name,
1681150
+ update: { status: "error", error: message }
1681151
+ });
1681152
+ return;
1681153
+ }
1681154
+ const task = taskGroup.getTask(target.name);
1681155
+ if (task == null) {
1681156
+ throw new Error(`Internal error; task '${target.name}' not found`);
1681157
+ }
1681158
+ taskGroup.updateTask({
1681159
+ id: target.name,
1681160
+ update: {
1681161
+ status: "running",
1681162
+ currentStep: `${target.image}:${target.version}`
1681163
+ }
1681164
+ });
1681165
+ const pipelineResult = await pipeline5.run({
1681166
+ organization: workspace.org,
1681167
+ ai: workspace.ai,
1681168
+ task,
1681169
+ target,
1681170
+ apiDefinition,
1681171
+ audiences: this.parseAudiences(args.audience),
1681172
+ runtime,
1681173
+ containerEngine: args["container-engine"] ?? "docker",
1681174
+ keepContainer: args["keep-container"],
1681175
+ preview: args.preview,
1681176
+ outputPath: args.output != null ? resolve5(context2.cwd, args.output) : void 0,
1681177
+ token,
1681178
+ version: args.version
1681179
+ });
1681180
+ if (!pipelineResult.success) {
1681181
+ taskGroup.updateTask({
1681182
+ id: target.name,
1681183
+ update: {
1681184
+ status: "error",
1681185
+ error: pipelineResult.error
1681186
+ }
1681187
+ });
1681188
+ return;
1681189
+ }
1681190
+ taskGroup.updateTask({
1681191
+ id: target.name,
1681192
+ update: {
1681193
+ status: "success",
1681194
+ output: pipelineResult.output
1681195
+ }
1681196
+ });
1681197
+ }));
1681198
+ const summary = taskGroup.complete({
1681199
+ successMessage: `Successfully generated ${this.maybePluralSdks(validTargets)}`,
1681200
+ errorMessage: `Failed to generate ${this.maybePluralSdks(validTargets)}`
1681201
+ });
1681202
+ if (summary.failedCount > 0) {
1681203
+ throw CliError.exit();
1681204
+ }
1681205
+ }
1681206
+ getTargets({ workspace, groupName, targetName }) {
1681207
+ const targets2 = workspace.sdks != null ? this.filterTargetsByGroup(workspace.sdks.targets, groupName) : [];
1681208
+ if (targetName != null) {
1681209
+ const filtered = targets2.filter((t2) => t2.name === targetName);
1681210
+ if (filtered.length === 0) {
1681211
+ throw new Error(`Target '${targetName}' not found`);
1681212
+ }
1681213
+ return filtered;
1681214
+ }
1681215
+ if (targets2.length === 0) {
1681216
+ if (groupName != null) {
1681217
+ throw new Error(`No targets found for group '${groupName}'`);
1681218
+ }
1681219
+ throw new Error("No targets configured in fern.yml");
1681220
+ }
1681221
+ return targets2;
1681222
+ }
1681223
+ /**
1681224
+ * Filter targets by group name. If no group is specified, returns all targets.
1681225
+ */
1681226
+ filterTargetsByGroup(targets2, groupName) {
1681227
+ if (groupName == null) {
1681228
+ return targets2;
1681229
+ }
1681230
+ return targets2.filter((target) => target.groups?.includes(groupName));
1681231
+ }
1681232
+ parseAudiences(audiences) {
1681233
+ if (audiences == null || audiences.length === 0) {
1681234
+ return void 0;
1681235
+ }
1681236
+ return {
1681237
+ type: "select",
1681238
+ audiences
1681239
+ };
1681240
+ }
1681241
+ validateArgs(args) {
1681242
+ if (args.output != null && !args.preview) {
1681243
+ throw new Error("The --output flag can only be used with --preview");
1681244
+ }
1681245
+ if (args["container-engine"] != null && !args.local) {
1681246
+ throw new Error("The --container-engine flag can only be used with --local");
1681247
+ }
1681248
+ if (args.group != null && args.target != null) {
1681249
+ throw new Error("The --group and --target flags cannot be used together");
1681250
+ }
1681251
+ if (args.group == null && args.target == null) {
1681252
+ throw new Error("A --target or --group must be specified");
1681253
+ }
1681254
+ }
1681255
+ maybePluralSdks(targets2) {
1681256
+ return targets2.length === 1 ? "SDK" : "SDKs";
1681257
+ }
1681258
+ };
1681065
1681259
  function addGenerateCommand(cli) {
1681066
- command2(cli, "generate", "Generate SDKs configured in fern.yml", handleGenerate, (yargs) => yargs.option("target", {
1681260
+ const cmd = new GenerateCommand();
1681261
+ command2(cli, "generate", "Generate SDKs configured in fern.yml", (context2, args) => cmd.handle(context2, args), (yargs) => yargs.option("target", {
1681067
1681262
  type: "string",
1681068
1681263
  description: "The SDK target to generate"
1681069
1681264
  }).option("group", {
@@ -1681100,167 +1681295,6 @@ function addGenerateCommand(cli) {
1681100
1681295
  description: "The version to use for the generated packages (e.g. 1.0.0)"
1681101
1681296
  }));
1681102
1681297
  }
1681103
- async function handleGenerate(context2, args) {
1681104
- validateArgs2(args);
1681105
- const workspace = await context2.loadWorkspaceOrThrow();
1681106
- if (workspace.sdks == null) {
1681107
- throw new Error("No SDKs configured in fern.yml");
1681108
- }
1681109
- const targets2 = getTargets({
1681110
- workspace,
1681111
- groupName: args.group ?? workspace.sdks.defaultGroup,
1681112
- targetName: args.target
1681113
- });
1681114
- const apisToCheck = [...new Set(targets2.map((t2) => t2.api))];
1681115
- const checker = new ApiChecker({
1681116
- context: context2,
1681117
- cliVersion: workspace.cliVersion
1681118
- });
1681119
- const checkResult = await checker.check({
1681120
- workspace,
1681121
- apiNames: apisToCheck
1681122
- });
1681123
- const validTargets = targets2.filter((t2) => checkResult.validApis.has(t2.api));
1681124
- if (validTargets.length === 0) {
1681125
- throw CliError.exit();
1681126
- }
1681127
- const pipeline5 = new GeneratorPipeline({
1681128
- context: context2,
1681129
- cliVersion: workspace.cliVersion
1681130
- });
1681131
- const token = args.local ? void 0 : await context2.getTokenOrPrompt();
1681132
- const runtime = args.local ? "local" : "remote";
1681133
- const taskGroup = new TaskGroup({ context: context2 });
1681134
- const skippedTargets = targets2.filter((t2) => checkResult.invalidApis.has(t2.api));
1681135
- for (const target of skippedTargets) {
1681136
- taskGroup.addTask({
1681137
- id: target.name,
1681138
- name: target.name,
1681139
- status: "skipped",
1681140
- skipReason: `API '${target.api}' has errors`
1681141
- });
1681142
- }
1681143
- for (const target of validTargets) {
1681144
- taskGroup.addTask({
1681145
- id: target.name,
1681146
- name: target.name
1681147
- });
1681148
- }
1681149
- await taskGroup.start({
1681150
- title: "Generating SDKs",
1681151
- subtitle: `org: ${workspace.sdks.org}`
1681152
- });
1681153
- await Promise.all(validTargets.map(async (target) => {
1681154
- const apiDefinition = workspace.apis[target.api];
1681155
- if (apiDefinition == null) {
1681156
- const message = `API '${target.api}' not found in workspace`;
1681157
- taskGroup.updateTask({
1681158
- id: target.name,
1681159
- update: { status: "error", error: message }
1681160
- });
1681161
- return;
1681162
- }
1681163
- const task = taskGroup.getTask(target.name);
1681164
- if (task == null) {
1681165
- throw new Error(`Internal error; task '${target.name}' not found`);
1681166
- }
1681167
- taskGroup.updateTask({
1681168
- id: target.name,
1681169
- update: {
1681170
- status: "running",
1681171
- currentStep: `${target.image}:${target.version}`
1681172
- }
1681173
- });
1681174
- const pipelineResult = await pipeline5.run({
1681175
- organization: workspace.org,
1681176
- ai: workspace.ai,
1681177
- task,
1681178
- target,
1681179
- apiDefinition,
1681180
- audiences: parseAudiences2(args.audience),
1681181
- runtime,
1681182
- containerEngine: args["container-engine"] ?? "docker",
1681183
- keepContainer: args["keep-container"] ?? false,
1681184
- preview: args.preview ?? false,
1681185
- outputPath: args.output != null ? resolve5(context2.cwd, args.output) : void 0,
1681186
- token,
1681187
- version: args.version
1681188
- });
1681189
- if (!pipelineResult.success) {
1681190
- taskGroup.updateTask({
1681191
- id: target.name,
1681192
- update: {
1681193
- status: "error",
1681194
- error: pipelineResult.error
1681195
- }
1681196
- });
1681197
- return;
1681198
- }
1681199
- taskGroup.updateTask({
1681200
- id: target.name,
1681201
- update: {
1681202
- status: "success",
1681203
- output: pipelineResult.output
1681204
- }
1681205
- });
1681206
- }));
1681207
- const summary = taskGroup.complete({
1681208
- successMessage: `Successfully generated ${maybePluralSdks(validTargets)}`,
1681209
- errorMessage: `Failed to generate ${maybePluralSdks(validTargets)}`
1681210
- });
1681211
- if (summary.failedCount > 0) {
1681212
- throw CliError.exit();
1681213
- }
1681214
- }
1681215
- function getTargets({ workspace, groupName, targetName }) {
1681216
- const targets2 = workspace.sdks != null ? filterTargetsByGroup(workspace.sdks.targets, groupName) : [];
1681217
- if (targetName != null) {
1681218
- const filtered = targets2.filter((t2) => t2.name === targetName);
1681219
- if (filtered.length === 0) {
1681220
- throw new Error(`Target '${targetName}' not found`);
1681221
- }
1681222
- return filtered;
1681223
- }
1681224
- if (targets2.length === 0) {
1681225
- if (groupName != null) {
1681226
- throw new Error(`No targets found for group '${groupName}'`);
1681227
- }
1681228
- throw new Error("No targets configured in fern.yml");
1681229
- }
1681230
- return targets2;
1681231
- }
1681232
- function filterTargetsByGroup(targets2, groupName) {
1681233
- if (groupName == null) {
1681234
- return targets2;
1681235
- }
1681236
- return targets2.filter((target) => target.groups?.includes(groupName));
1681237
- }
1681238
- function parseAudiences2(audiences) {
1681239
- if (audiences == null || audiences.length === 0) {
1681240
- return void 0;
1681241
- }
1681242
- return {
1681243
- type: "select",
1681244
- audiences
1681245
- };
1681246
- }
1681247
- function validateArgs2(args) {
1681248
- if (args.output != null && !args.preview) {
1681249
- throw new Error("The --output flag can only be used with --preview");
1681250
- }
1681251
- if (args["container-engine"] != null && !args.local) {
1681252
- throw new Error("The --container-engine flag can only be used with --local");
1681253
- }
1681254
- if (args.group != null && args.target != null) {
1681255
- throw new Error("The --group and --target flags cannot be used together");
1681256
- }
1681257
- if (args.group == null && args.target == null) {
1681258
- throw new Error("A --target or --group must be specified");
1681259
- }
1681260
- }
1681261
- function maybePluralSdks(targets2) {
1681262
- return targets2.length === 1 ? "SDK" : "SDKs";
1681263
- }
1681264
1681298
 
1681265
1681299
  // ../cli-v2/lib/commands/sdk/command.js
1681266
1681300
  function addSdkCommand(cli) {
@@ -1712107,7 +1712141,7 @@ var CliContext = class {
1712107
1712141
  if (false) {
1712108
1712142
  this.logger.error("CLI_VERSION is not defined");
1712109
1712143
  }
1712110
- return "3.63.0";
1712144
+ return "3.64.0";
1712111
1712145
  }
1712112
1712146
  getCliName() {
1712113
1712147
  if (false) {
@@ -1715221,7 +1715255,7 @@ var import_path56 = __toESM(require("path"), 1);
1715221
1715255
  var LOCAL_STORAGE_FOLDER4 = ".fern-dev";
1715222
1715256
  var LOGS_FOLDER_NAME = "logs";
1715223
1715257
  function getCliSource() {
1715224
- const version7 = "3.63.0";
1715258
+ const version7 = "3.64.0";
1715225
1715259
  return `cli@${version7}`;
1715226
1715260
  }
1715227
1715261
  var DebugLogger = class {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.63.0",
2
+ "version": "3.64.0",
3
3
  "repository": {
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/fern-api/fern.git",