@postman/sdk-config 0.10.1 → 0.11.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 (36) hide show
  1. package/README.md +6 -0
  2. package/dist/index.cjs +697 -34
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +3 -3
  5. package/dist/index.d.ts +3 -3
  6. package/dist/index.js +683 -35
  7. package/dist/index.js.map +1 -1
  8. package/dist/sdk-config/index.cjs +649 -34
  9. package/dist/sdk-config/index.cjs.map +1 -1
  10. package/dist/sdk-config/index.d.cts +2 -2
  11. package/dist/sdk-config/index.d.ts +2 -2
  12. package/dist/sdk-config/index.js +642 -35
  13. package/dist/sdk-config/index.js.map +1 -1
  14. package/dist/sdk-config/v1/index.cjs +649 -34
  15. package/dist/sdk-config/v1/index.cjs.map +1 -1
  16. package/dist/sdk-config/v1/index.d.cts +2858 -2377
  17. package/dist/sdk-config/v1/index.d.ts +2858 -2377
  18. package/dist/sdk-config/v1/index.js +642 -35
  19. package/dist/sdk-config/v1/index.js.map +1 -1
  20. package/dist/sdk-config-ir/index.cjs +247 -4
  21. package/dist/sdk-config-ir/index.cjs.map +1 -1
  22. package/dist/sdk-config-ir/index.d.cts +2 -2
  23. package/dist/sdk-config-ir/index.d.ts +2 -2
  24. package/dist/sdk-config-ir/index.js +241 -5
  25. package/dist/sdk-config-ir/index.js.map +1 -1
  26. package/dist/sdk-config-ir/v1/index.cjs +247 -4
  27. package/dist/sdk-config-ir/v1/index.cjs.map +1 -1
  28. package/dist/sdk-config-ir/v1/index.d.cts +3109 -2960
  29. package/dist/sdk-config-ir/v1/index.d.ts +3109 -2960
  30. package/dist/sdk-config-ir/v1/index.js +241 -5
  31. package/dist/sdk-config-ir/v1/index.js.map +1 -1
  32. package/dist/{typescript-Chge0X4f.d.cts → typescript-CsAa1VSy.d.cts} +81 -1
  33. package/dist/{typescript-Chge0X4f.d.ts → typescript-CsAa1VSy.d.ts} +81 -1
  34. package/package.json +1 -1
  35. package/src/sdk-config/v1/README.md +183 -1
  36. package/src/sdk-config-ir/v1/README.md +29 -1
package/dist/index.cjs CHANGED
@@ -131,13 +131,21 @@ var oauthScopeSchema = zod.z.strictObject({
131
131
  name: nonEmptyStringSchema.describe("The OAuth scope value requested from the provider."),
132
132
  description: zod.z.string().optional().describe("A description of the OAuth scope included in generated SDK documentation.")
133
133
  });
134
+ var publicClientIdSchema = nonEmptyStringSchema.refine((value) => value.trim() === value, {
135
+ message: "must not have leading or trailing whitespace"
136
+ }).refine((value) => !value.includes("${"), {
137
+ message: "must be a literal public client ID, not an environment expression"
138
+ });
134
139
  var oauthFlowSchema = zod.z.discriminatedUnion("type", [
135
140
  zod.z.strictObject({
136
141
  type: zod.z.literal("authorization-code").describe("Uses the OAuth authorization code flow."),
137
142
  authorizationUrl: nonEmptyStringSchema.describe("The URL used to authorize the client."),
138
143
  tokenUrl: nonEmptyStringSchema.describe("The URL used to exchange a code for tokens."),
139
144
  refreshUrl: nonEmptyStringSchema.optional().describe("The URL used to refresh access tokens."),
140
- scopes: zod.z.array(oauthScopeSchema).optional().describe("The scopes supported by this flow.")
145
+ scopes: zod.z.array(oauthScopeSchema).optional().describe("The scopes supported by this flow."),
146
+ clientId: publicClientIdSchema.optional().describe(
147
+ "The public, non-secret OAuth client ID that generated interactive login flows, such as CLI browser login with PKCE, send to the authorization and token endpoints. It is embedded verbatim in generated code, so it must never be a client secret."
148
+ )
141
149
  }),
142
150
  zod.z.strictObject({
143
151
  type: zod.z.literal("client-credentials").describe("Uses the OAuth client credentials flow."),
@@ -453,8 +461,102 @@ var packageConfigSchema = zod.z.strictObject({
453
461
  projectUrls: zod.z.array(projectUrlSchema).optional().describe("Labeled project links for package metadata."),
454
462
  extraDependencies: zod.z.array(dependencySchema).optional().describe("Additional runtime dependencies added to the generated package."),
455
463
  extraDevDependencies: zod.z.array(dependencySchema).optional().describe("Additional development dependencies added to the generated package."),
456
- extraPeerDependencies: zod.z.array(dependencySchema).optional().describe("Additional peer dependencies added to the generated package.")
464
+ extraPeerDependencies: zod.z.array(dependencySchema).optional().describe("Additional peer dependencies added to the generated package."),
465
+ extraPeerDependenciesMeta: zod.z.record(nonEmptyStringSchema, jsonObjectSchema).optional().describe(
466
+ "npm peerDependenciesMeta entries keyed by peer dependency name, such as { optional: true }."
467
+ )
457
468
  });
469
+ var GITHUB_ACTIONS_SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
470
+ var GITHUB_REPOSITORY_SLUG_PATTERN = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
471
+ var HOMEBREW_FORMULA_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
472
+ var githubActionsSecretNameSchema = zod.z.string({ error: "must be the name of a GitHub Actions secret" }).regex(GITHUB_ACTIONS_SECRET_NAME_PATTERN, {
473
+ error: "must be the name of a GitHub Actions secret: start with an uppercase letter and contain only A-Z, 0-9, or _. Secret values and ${...} expressions are not accepted."
474
+ }).refine((value) => value !== "GITHUB_TOKEN", {
475
+ error: "GITHUB_TOKEN cannot be used: it is the workflow's built-in token, scoped to the generated repository. Store the credential under a different secret name."
476
+ });
477
+ var githubRepositorySlugSchema = zod.z.string({ error: 'must be a GitHub repository in "<owner>/<repo>" form' }).regex(GITHUB_REPOSITORY_SLUG_PATTERN, {
478
+ error: 'must be a GitHub repository in "<owner>/<repo>" form, for example "acme/homebrew-tap"'
479
+ });
480
+ var homebrewFormulaNameSchema = zod.z.string({ error: "must be a Homebrew formula name" }).regex(HOMEBREW_FORMULA_NAME_PATTERN, {
481
+ error: "must be a Homebrew formula name: start with a lowercase letter and contain only a-z, 0-9, or -"
482
+ });
483
+ var cliDistributionGithubAppSchema = zod.z.strictObject({
484
+ appIdSecretName: githubActionsSecretNameSchema.describe(
485
+ "The name of the GitHub Actions secret holding the GitHub App ID or client ID."
486
+ ),
487
+ privateKeySecretName: githubActionsSecretNameSchema.describe(
488
+ "The name of the GitHub Actions secret holding the GitHub App private key in PEM form."
489
+ )
490
+ });
491
+ var channelTokenSecretNameDescription = "The name of the GitHub Actions secret holding a token with write access to the channel repository. Takes precedence over githubApp for this channel.";
492
+ var cliDistributionHomebrewSchema = zod.z.strictObject({
493
+ tap: githubRepositorySlugSchema.describe(
494
+ 'The Homebrew tap repository in "<owner>/<repo>" form that receives the formula.'
495
+ ),
496
+ formula: homebrewFormulaNameSchema.optional().describe("The Homebrew formula name; the generator defaults it to the CLI binary name."),
497
+ tokenSecretName: githubActionsSecretNameSchema.optional().describe(channelTokenSecretNameDescription)
498
+ });
499
+ var cliDistributionScoopSchema = zod.z.strictObject({
500
+ bucket: githubRepositorySlugSchema.describe(
501
+ 'The Scoop bucket repository in "<owner>/<repo>" form that receives the manifest.'
502
+ ),
503
+ tokenSecretName: githubActionsSecretNameSchema.optional().describe(channelTokenSecretNameDescription)
504
+ });
505
+ var cliDistributionConfigSchema = zod.z.strictObject({
506
+ githubApp: cliDistributionGithubAppSchema.optional().describe(
507
+ "A GitHub App used to mint short-lived tokens for every channel without its own tokenSecretName."
508
+ ),
509
+ homebrew: cliDistributionHomebrewSchema.optional().describe("Publishes a Homebrew formula to a tap repository on each tagged release."),
510
+ scoop: cliDistributionScoopSchema.optional().describe("Publishes a Scoop manifest to a bucket repository on each tagged release.")
511
+ }).superRefine((distribution, context) => {
512
+ if (distribution.homebrew !== void 0 || distribution.scoop !== void 0) {
513
+ return;
514
+ }
515
+ if (distribution.githubApp !== void 0) {
516
+ context.addIssue({
517
+ code: "custom",
518
+ message: "githubApp requires at least one distribution channel: homebrew or scoop",
519
+ path: ["githubApp"]
520
+ });
521
+ return;
522
+ }
523
+ context.addIssue({
524
+ code: "custom",
525
+ message: "distribution must configure at least one channel: homebrew or scoop"
526
+ });
527
+ });
528
+ var CLI_DISTRIBUTION_REQUIRES_GITHUB_DELIVERY_MESSAGE = 'distribution requires output.delivery "github": Homebrew and Scoop publish from a tagged GitHub Release produced by the generated release workflow. Set delivery to "github" or remove distribution.';
529
+ var CLI_PUBLISH_REQUIRES_GITHUB_DELIVERY_MESSAGE = 'package publication for target language "cli" requires output.delivery "github": the CLI generator publishes npm packages only from its generated GitHub workflow.';
530
+ var CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE = "CLI_DISTRIBUTION_NON_RELEASE_MODE";
531
+ var nonReleaseGithubModes = /* @__PURE__ */ new Set(["pull-request", "push", "commit"]);
532
+ function cliDistributionModeDiagnostic(output, outputPath) {
533
+ const mode = output?.github?.mode;
534
+ if (output?.distribution === void 0 || mode === void 0 || !nonReleaseGithubModes.has(mode)) {
535
+ return void 0;
536
+ }
537
+ return {
538
+ code: CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE,
539
+ severity: "warning",
540
+ path: [...outputPath, "github", "mode"],
541
+ reason: `GitHub mode "${mode}" does not create a release tag, so Homebrew and Scoop publish only after a semantic-version tag is pushed to the repository.`,
542
+ suggestedAction: 'Use mode "release" or "commit-and-release", or push a version tag after merging generated changes.'
543
+ };
544
+ }
545
+
546
+ // src/sdk-config/v1/diagnostics.ts
547
+ function getSdkConfigV1Diagnostics(config) {
548
+ return config.targets.flatMap((target, targetIndex) => {
549
+ if (target.language !== "cli") {
550
+ return [];
551
+ }
552
+ const diagnostic = cliDistributionModeDiagnostic(target.output, [
553
+ "targets",
554
+ targetIndex,
555
+ "output"
556
+ ]);
557
+ return diagnostic ? [diagnostic] : [];
558
+ });
559
+ }
458
560
  var httpMethodSchema = zod.z.enum([
459
561
  "GET",
460
562
  "POST",
@@ -659,6 +761,17 @@ function stringValue(value) {
659
761
  function stringArrayValue(value) {
660
762
  return Array.isArray(value) && value.every((item) => typeof item === "string" && item.length > 0) ? value : void 0;
661
763
  }
764
+ var canonicalLicenseTypes = {
765
+ mit: "MIT",
766
+ apache: "APACHE",
767
+ "apache-2.0": "APACHE",
768
+ "gpl-3.0": "GPL3",
769
+ "gpl-3.0-only": "GPL3",
770
+ unlicensed: "UNLICENSED"
771
+ };
772
+ function canonicalLicenseType(value) {
773
+ return canonicalLicenseTypes[value.trim().toLowerCase()];
774
+ }
662
775
  function stableJson(value) {
663
776
  return JSON.stringify(sortKeys(value));
664
777
  }
@@ -669,6 +782,280 @@ function sortKeys(value) {
669
782
  Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, sortKeys(child)])
670
783
  );
671
784
  }
785
+ var ALPHANUMERIC_PATTERN = /[A-Za-z0-9]/;
786
+ var ROOT_GROUP_PATTERN = /^[a-z][a-z0-9_-]*$/;
787
+ var KEBAB_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
788
+ var DOTTED_COMMAND_PATH_PATTERN = /^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/;
789
+ var FIELD_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
790
+ var RESERVED_USER_AGENT_SUFFIX_FLAGS = /* @__PURE__ */ new Set([
791
+ "params",
792
+ "output",
793
+ "json",
794
+ "format",
795
+ "dry-run",
796
+ "base-url",
797
+ "page-all",
798
+ "page-limit",
799
+ "page-delay",
800
+ "no-pager",
801
+ "no-extract",
802
+ "no-retry",
803
+ "no-stream",
804
+ "quiet",
805
+ "query",
806
+ "help",
807
+ "debug",
808
+ "schema"
809
+ ]);
810
+ var RESERVED_PROFILES_COMMAND_NAMES = /* @__PURE__ */ new Set([
811
+ "auth",
812
+ "completion",
813
+ "man",
814
+ "errors",
815
+ "generate-skills",
816
+ "help"
817
+ ]);
818
+ var binaryNameSchema = nonEmptyStringSchema.regex(ALPHANUMERIC_PATTERN, {
819
+ message: "binaryName must contain at least one ASCII letter or digit"
820
+ });
821
+ var rootGroupSchema = zod.z.string().regex(ROOT_GROUP_PATTERN, {
822
+ message: "rootGroup must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores"
823
+ });
824
+ var userAgentSuffixFlagSchema = zod.z.string().superRefine((value, context) => {
825
+ if (value.startsWith("-")) {
826
+ context.addIssue({
827
+ code: "custom",
828
+ message: 'userAgentSuffixFlag must be the long flag name without the leading "--"'
829
+ });
830
+ } else if (!KEBAB_NAME_PATTERN.test(value)) {
831
+ context.addIssue({
832
+ code: "custom",
833
+ message: "userAgentSuffixFlag must start with a lowercase letter and contain only lowercase letters, digits, and hyphens"
834
+ });
835
+ } else if (RESERVED_USER_AGENT_SUFFIX_FLAGS.has(value)) {
836
+ context.addIssue({
837
+ code: "custom",
838
+ message: `userAgentSuffixFlag "${value}" collides with a built-in global flag`
839
+ });
840
+ }
841
+ });
842
+ var profilesCommandNameSchema = zod.z.string().superRefine((value, context) => {
843
+ if (!KEBAB_NAME_PATTERN.test(value)) {
844
+ context.addIssue({
845
+ code: "custom",
846
+ message: "profiles.commandName must start with a lowercase letter and contain only lowercase letters, digits, and hyphens"
847
+ });
848
+ } else if (RESERVED_PROFILES_COMMAND_NAMES.has(value)) {
849
+ context.addIssue({
850
+ code: "custom",
851
+ message: `profiles.commandName "${value}" collides with a built-in command group`
852
+ });
853
+ }
854
+ });
855
+ function dottedCommandPathSchema(field) {
856
+ return zod.z.string().regex(DOTTED_COMMAND_PATH_PATTERN, {
857
+ message: `${field} must be a dotted command path such as "iam.keys.create"`
858
+ });
859
+ }
860
+ function fieldNameMapSchema(field) {
861
+ const message = `${field} keys and values must be field names containing only [A-Za-z0-9_.-]`;
862
+ return zod.z.record(zod.z.string(), zod.z.string().regex(FIELD_NAME_PATTERN, { message })).superRefine((value, context) => {
863
+ for (const key of Object.keys(value)) {
864
+ if (!FIELD_NAME_PATTERN.test(key)) {
865
+ context.addIssue({ code: "custom", message, path: [key] });
866
+ }
867
+ }
868
+ });
869
+ }
870
+ var profilesProvisionOperationSchema = zod.z.strictObject({
871
+ operation: dottedCommandPathSchema("profiles.provisionOperation.operation").describe(
872
+ "The dotted command path of the operation that mints a profile credential."
873
+ ),
874
+ credential: fieldNameMapSchema("profiles.provisionOperation.credential").refine((value) => Object.keys(value).length > 0, {
875
+ message: "profiles.provisionOperation.credential must map at least one credential field"
876
+ }).describe("Maps each stored credential field to the response field that supplies it."),
877
+ revokeParameters: fieldNameMapSchema("profiles.provisionOperation.revokeParameters").optional().describe("Maps each revoke-operation parameter to the response field that supplies it.")
878
+ });
879
+ var profilesConfigSchema = zod.z.strictObject({
880
+ enabled: zod.z.boolean().describe("Whether the CLI emits profile commands and the global --profile flag."),
881
+ commandName: profilesCommandNameSchema.optional().describe('The profile command group name. The generator defaults to "profiles".'),
882
+ revokeOperation: dottedCommandPathSchema("profiles.revokeOperation").optional().describe('The dotted command path called by "profiles remove --revoke".'),
883
+ provisionOperation: profilesProvisionOperationSchema.optional().describe('The operation called by "profiles create --provision" and its response mapping.')
884
+ });
885
+ var cliGenerationConfigSchema = zod.z.strictObject({
886
+ paginationParameters: zod.z.array(nonEmptyStringSchema).optional().describe("Request parameter names treated as pagination controls by the CLI."),
887
+ skills: zod.z.boolean().optional().describe("Whether the generated CLI includes skills that teach AI agents to invoke commands."),
888
+ binaryName: binaryNameSchema.optional().describe(
889
+ "The CLI executable name. The generator kebab-cases it and also uses it for the source directory and env-var prefix."
890
+ ),
891
+ customCommands: zod.z.boolean().optional().describe("Whether hand-written command support is generated. The generator defaults to true."),
892
+ rootGroup: rootGroupSchema.optional().describe("A command group that every spec-derived command is nested under."),
893
+ profiles: profilesConfigSchema.optional().describe("Named profile command configuration."),
894
+ splitTypeCrates: zod.z.boolean().optional().describe("Whether generated types are split into one crate per API behind a facade crate."),
895
+ userAgentSuffixFlag: userAgentSuffixFlagSchema.optional().describe('The long flag name, without "--", that appends a product token to the User-Agent.')
896
+ });
897
+
898
+ // src/sdk-config/v1/fern-config-mapper-cli.ts
899
+ var CLI_GENERATION_FIELDS = [
900
+ "binaryName",
901
+ "customCommands",
902
+ "rootGroup",
903
+ "profiles",
904
+ "splitTypeCrates",
905
+ "userAgentSuffixFlag"
906
+ ];
907
+ var PROFILES_FIELDS = ["enabled", "commandName", "revokeOperation"];
908
+ var PROVISION_OPERATION_FIELDS = ["operation", "credential", "revokeParameters"];
909
+ function mapCliGeneration(config, state, basePath, targetIndex) {
910
+ const generation = {};
911
+ for (const field of CLI_GENERATION_FIELDS) {
912
+ const raw = ownValue(config, field);
913
+ if (raw === void 0) continue;
914
+ const fieldPath = [...basePath, field];
915
+ const { value, consumedPaths } = field === "profiles" && isObject(raw) ? pickProfiles(raw, fieldPath) : { value: raw, consumedPaths: [fieldPath] };
916
+ const parsed = cliGenerationConfigSchema.shape[field].safeParse(value);
917
+ consumedPaths.forEach((path) => consume(state, path));
918
+ if (parsed.success) {
919
+ generation[field] = structuredClone(value);
920
+ continue;
921
+ }
922
+ const diagnostics = parsed.error.issues.map(
923
+ (issue) => invalidValueDiagnostic(field, fieldPath, issue.path, issue.message, targetIndex)
924
+ );
925
+ (state.valueDiagnostics ??= []).push(...diagnostics);
926
+ }
927
+ return generation;
928
+ }
929
+ function pickProfiles(profiles, path) {
930
+ const picked = pickKnown(profiles, PROFILES_FIELDS, path);
931
+ const provisionOperation = ownValue(profiles, "provisionOperation");
932
+ const provisionPath = [...path, "provisionOperation"];
933
+ if (isObject(provisionOperation)) {
934
+ const provision = pickKnown(provisionOperation, PROVISION_OPERATION_FIELDS, provisionPath);
935
+ picked.value.provisionOperation = provision.value;
936
+ picked.consumedPaths.push(...provision.consumedPaths);
937
+ } else if (provisionOperation !== void 0) {
938
+ picked.value.provisionOperation = provisionOperation;
939
+ picked.consumedPaths.push(provisionPath);
940
+ }
941
+ return { value: { enabled: false, ...picked.value }, consumedPaths: picked.consumedPaths };
942
+ }
943
+ function pickKnown(value, fields, path) {
944
+ const picked = {};
945
+ const consumedPaths = [];
946
+ for (const field of fields) {
947
+ const child = ownValue(value, field);
948
+ if (child === void 0) continue;
949
+ picked[field] = child;
950
+ consumedPaths.push([...path, field]);
951
+ }
952
+ return { value: picked, consumedPaths };
953
+ }
954
+ function ownValue(value, key) {
955
+ return Object.hasOwn(value, key) ? value[key] : void 0;
956
+ }
957
+ function invalidValueDiagnostic(field, fieldPath, issuePath, message, targetIndex) {
958
+ const relative = issuePath.map((part) => typeof part === "symbol" ? String(part) : part);
959
+ const sdkConfigField = ["targets", targetIndex, "generation", field];
960
+ return {
961
+ code: "FERN_CONFIG_VALUE_INVALID",
962
+ severity: "warning",
963
+ path: [...fieldPath, ...relative],
964
+ reason: `CLI setting ${field} was not migrated because SDK Config rejects it: ${message}`,
965
+ sdkConfigPath: [...sdkConfigField, ...relative],
966
+ suggestedAction: `Correct the value, then set ${sdkConfigField.join(".")} manually.`
967
+ };
968
+ }
969
+
970
+ // src/sdk-config/v1/fern-config-mapper-cli-distribution.ts
971
+ var DISTRIBUTION_KEYS = {
972
+ githubApp: { appIdSecret: "appIdSecretName", privateKeySecret: "privateKeySecretName" },
973
+ homebrew: { tap: "tap", formula: "formula", tokenEnvironmentVariable: "tokenSecretName" },
974
+ scoop: { bucket: "bucket", tokenEnvironmentVariable: "tokenSecretName" }
975
+ };
976
+ function mapCliDistribution(config, state, basePath, targetIndex) {
977
+ if (!Object.hasOwn(config, "distribution")) return;
978
+ const raw = config.distribution;
979
+ const path = [...basePath, "distribution"];
980
+ const translated = isObject(raw) ? translateDistribution(raw, path) : { value: raw, consumedPaths: [path], legacyKeys: /* @__PURE__ */ new Map() };
981
+ const parsed = cliDistributionConfigSchema.safeParse(translated.value);
982
+ translated.consumedPaths.forEach((consumedPath) => consume(state, consumedPath));
983
+ if (parsed.success) {
984
+ state.cliDistribution = { value: parsed.data, path };
985
+ return;
986
+ }
987
+ const diagnostics = parsed.error.issues.map(
988
+ (issue) => invalidDistributionDiagnostic(issue, path, translated.legacyKeys, targetIndex)
989
+ );
990
+ const reportedPaths = /* @__PURE__ */ new Set();
991
+ (state.valueDiagnostics ??= []).push(
992
+ ...diagnostics.filter(({ path: diagnosticPath }) => {
993
+ const key = diagnosticPath.join(".");
994
+ if (reportedPaths.has(key)) return false;
995
+ reportedPaths.add(key);
996
+ return true;
997
+ })
998
+ );
999
+ }
1000
+ function translateDistribution(distribution, path) {
1001
+ const value = {};
1002
+ const consumedPaths = [];
1003
+ const legacyKeys = /* @__PURE__ */ new Map();
1004
+ for (const [block, keys] of Object.entries(DISTRIBUTION_KEYS)) {
1005
+ if (!Object.hasOwn(distribution, block)) continue;
1006
+ const blockValue = distribution[block];
1007
+ const blockPath = [...path, block];
1008
+ if (!isObject(blockValue)) {
1009
+ value[block] = blockValue;
1010
+ consumedPaths.push(blockPath);
1011
+ continue;
1012
+ }
1013
+ const translatedBlock = {};
1014
+ for (const [legacyKey, sdkConfigKey] of Object.entries(keys)) {
1015
+ if (!Object.hasOwn(blockValue, legacyKey)) continue;
1016
+ translatedBlock[sdkConfigKey] = blockValue[legacyKey];
1017
+ consumedPaths.push([...blockPath, legacyKey]);
1018
+ legacyKeys.set(`${block}.${sdkConfigKey}`, legacyKey);
1019
+ }
1020
+ value[block] = translatedBlock;
1021
+ }
1022
+ return { value, consumedPaths, legacyKeys };
1023
+ }
1024
+ function invalidDistributionDiagnostic(issue, path, legacyKeys, targetIndex) {
1025
+ const relative = issue.path.map((part) => typeof part === "symbol" ? String(part) : part);
1026
+ const [block, field] = relative;
1027
+ const legacyField = typeof block === "string" && typeof field === "string" ? legacyKeys.get(`${block}.${field}`) : void 0;
1028
+ const legacyRelative = typeof block === "string" && legacyField !== void 0 ? [block, legacyField] : relative;
1029
+ const sdkConfigField = ["targets", targetIndex, "output", "distribution"];
1030
+ return {
1031
+ code: "FERN_CONFIG_VALUE_INVALID",
1032
+ severity: "warning",
1033
+ path: [...path, ...legacyRelative],
1034
+ reason: `CLI distribution was not migrated because SDK Config rejects it: ${issue.message}`,
1035
+ sdkConfigPath: [...sdkConfigField, ...relative],
1036
+ suggestedAction: `Correct the value, then set ${sdkConfigField.join(".")} manually.`
1037
+ };
1038
+ }
1039
+ function applyCliDistribution(output, pending, targetIndex) {
1040
+ if (pending === void 0) return { output, diagnostics: [] };
1041
+ if (output.delivery === "github") {
1042
+ return { output: { ...output, distribution: pending.value }, diagnostics: [] };
1043
+ }
1044
+ const outputPath = ["targets", targetIndex, "output"];
1045
+ return {
1046
+ output,
1047
+ diagnostics: [
1048
+ {
1049
+ code: "FERN_CLI_DISTRIBUTION_REQUIRES_GITHUB_OUTPUT",
1050
+ severity: "warning",
1051
+ path: pending.path,
1052
+ reason: `The CLI generator ignores distribution for "${output.delivery}" output, and SDK Config accepts distribution only with output.delivery "github", so it was not migrated`,
1053
+ sdkConfigPath: [...outputPath, "distribution"],
1054
+ suggestedAction: `Set ${outputPath.join(".")}.delivery to "github" for the CLI repository and add ${outputPath.join(".")}.distribution manually, or remove distribution.`
1055
+ }
1056
+ ]
1057
+ };
1058
+ }
672
1059
 
673
1060
  // src/sdk-config/v1/fern-config-mapper-output.ts
674
1061
  function mapOutput(generator, language, index) {
@@ -879,11 +1266,10 @@ function githubOutput(value, publishInfo, rawOutput, language, sourcePath, state
879
1266
  ...optionalObject("package", { ...publication?.package, ...licensePackage })
880
1267
  };
881
1268
  }
882
- var basicLicenseTypes = { mit: "MIT", apache: "APACHE" };
883
1269
  function mapGithubLicense(value, sourcePath, state) {
884
1270
  if (!isObject(value) || stringValue(value.type) !== "basic") return {};
885
1271
  const id = stringValue(value.id);
886
- const type = id ? basicLicenseTypes[id.toLowerCase()] : void 0;
1272
+ const type = id ? canonicalLicenseType(id) : void 0;
887
1273
  if (!type) return {};
888
1274
  consume(state, [...sourcePath, "type"]);
889
1275
  consume(state, [...sourcePath, "id"]);
@@ -1450,6 +1836,114 @@ function outputDiagnostic(path, index) {
1450
1836
  suggestedAction: resolvedGuidance?.suggestedAction ?? "Review this output setting and preserve it outside SDK Config when no equivalent exists."
1451
1837
  };
1452
1838
  }
1839
+
1840
+ // src/sdk-config/v1/package.ts
1841
+ var sdkConfigV1DependencySchema = dependencySchema;
1842
+ var sdkConfigV1PackageConfigSchema = packageConfigSchema;
1843
+
1844
+ // src/sdk-config/v1/fern-config-mapper-package.ts
1845
+ var emailSchema = zod.z.email();
1846
+ function mapCliPackageIdentity(identity, state, targetIndex) {
1847
+ mapIdentityField(identity, "homepage", stringValue, state);
1848
+ mapIdentityField(identity, "keywords", (value) => stringArrayValue(value)?.slice(), state);
1849
+ mapCargoAuthors(identity, state, targetIndex);
1850
+ mapIdentityField(identity, "license", licenseValue, state);
1851
+ }
1852
+ function mapIdentityField(identity, field, read, state) {
1853
+ const located = locate(identity.value, [field], identity.path);
1854
+ const value = located && read(located.value);
1855
+ if (located && value !== void 0) addPackageFallback(state, field, value, located.path);
1856
+ }
1857
+ function mapLicenseFallback(config, aliases, state, basePath) {
1858
+ const located = locate(config, aliases, basePath);
1859
+ const license = located && licenseValue(located.value);
1860
+ if (located && license) addPackageFallback(state, "license", license, located.path);
1861
+ }
1862
+ function resolveTargetPackage(targetPackage, fallbacks, generator, delivery, index) {
1863
+ const diagnostics = [];
1864
+ for (const fallback of fallbacks) {
1865
+ applyFallback(targetPackage, fallback, index, diagnostics);
1866
+ }
1867
+ if (delivery !== "github") {
1868
+ applyMetadataLicense(targetPackage, generator.raw, index, diagnostics);
1869
+ }
1870
+ return diagnostics;
1871
+ }
1872
+ function applyFallback(targetPackage, { field, value, path }, index, diagnostics) {
1873
+ const existing = targetPackage[field];
1874
+ if (existing === void 0) {
1875
+ targetPackage[field] = value;
1876
+ } else if (stableJson(existing) !== stableJson(value)) {
1877
+ diagnostics.push({
1878
+ code: "FERN_PACKAGE_VALUE_CONFLICT",
1879
+ severity: "warning",
1880
+ path,
1881
+ reason: `Fern value conflicts with the package.${field} already migrated for this target, which is kept`,
1882
+ sdkConfigPath: ["targets", index, "package", field],
1883
+ suggestedAction: `Choose the intended value and set targets.${index}.package.${field} manually.`
1884
+ });
1885
+ }
1886
+ }
1887
+ function applyMetadataLicense(targetPackage, raw, index, diagnostics) {
1888
+ const metadata = isObject(raw) && isObject(raw.metadata) ? raw.metadata : void 0;
1889
+ if (metadata?.license === void 0 || metadata.license === null) return;
1890
+ const path = ["group", "generators", index, "metadata", "license"];
1891
+ const license = licenseValue(metadata.license);
1892
+ if (license) {
1893
+ applyFallback(targetPackage, { field: "license", value: license, path }, index, diagnostics);
1894
+ return;
1895
+ }
1896
+ diagnostics.push({
1897
+ code: "FERN_CONFIG_FIELD_UNSUPPORTED",
1898
+ severity: "warning",
1899
+ path,
1900
+ reason: isObject(metadata.license) ? "A custom license file cannot be migrated automatically" : "metadata.license is not a license identifier",
1901
+ sdkConfigPath: ["targets", index, "package", "license"],
1902
+ suggestedAction: `Set targets.${index}.package.license manually.`
1903
+ });
1904
+ }
1905
+ function mapCargoAuthors(identity, state, targetIndex) {
1906
+ const located = locate(identity.value, ["authors"], identity.path);
1907
+ const entries = located && stringArrayValue(located.value);
1908
+ if (!located || !entries) return;
1909
+ consume(state, located.path);
1910
+ const authors = entries.map(parseCargoAuthor);
1911
+ const parsed = sdkConfigV1PackageConfigSchema.shape.authors.safeParse(authors);
1912
+ const invalid = parsed.success ? [] : [...new Set(parsed.error.issues.map((issue) => issue.path[0]))].filter(
1913
+ (index) => typeof index === "number"
1914
+ );
1915
+ if (invalid.length === 0) {
1916
+ addPackageFallback(state, "authors", authors, located.path);
1917
+ return;
1918
+ }
1919
+ const authorsPath = ["targets", targetIndex, "package", "authors"];
1920
+ (state.valueDiagnostics ??= []).push(
1921
+ ...invalid.map((entry) => ({
1922
+ code: "FERN_CONFIG_VALUE_INVALID",
1923
+ severity: "warning",
1924
+ path: [...located.path, entry],
1925
+ reason: 'CLI packageIdentity.authors was not migrated because this entry is not "Name" or "Name <email>" with a valid email',
1926
+ sdkConfigPath: authorsPath,
1927
+ suggestedAction: `Correct the entry, then set ${authorsPath.join(".")} manually.`
1928
+ }))
1929
+ );
1930
+ }
1931
+ function parseCargoAuthor(entry) {
1932
+ const trimmed = entry.trim();
1933
+ const match = /^(.*?)\s*<([^<>]*)>$/.exec(trimmed);
1934
+ if (!match) return { name: trimmed };
1935
+ const [, name = "", email = ""] = match;
1936
+ if (name !== "" && !emailSchema.safeParse(email).success) return { name: trimmed };
1937
+ return { name, email };
1938
+ }
1939
+ function licenseValue(value) {
1940
+ const license = stringValue(value)?.trim();
1941
+ return license ? { type: canonicalLicenseType(license) ?? license } : void 0;
1942
+ }
1943
+ function addPackageFallback(state, field, value, path) {
1944
+ consume(state, path);
1945
+ (state.packageFallbacks ??= []).push({ field, value, path });
1946
+ }
1453
1947
  var OMIT = /* @__PURE__ */ Symbol("omit");
1454
1948
  function inputJsonSchema(schema) {
1455
1949
  return zod.z.toJSONSchema(schema, {
@@ -1719,7 +2213,16 @@ var sdkConfigV1PublishConfigSchema = zod.z.discriminatedUnion("registry", [
1719
2213
  zod.z.strictObject({
1720
2214
  registry: zod.z.literal("npm").describe("Publishes the package to an npm-compatible registry."),
1721
2215
  token: nonEmptyStringSchema.optional().describe("The npm registry token, or an environment expression that resolves to it."),
2216
+ trustedPublishing: zod.z.boolean().optional().describe("Whether npm publication uses trusted publishing (OIDC) instead of a token."),
1722
2217
  ...commonPublishShape
2218
+ }).superRefine((publish, context) => {
2219
+ if (publish.trustedPublishing === true && publish.token !== void 0) {
2220
+ context.addIssue({
2221
+ code: "custom",
2222
+ message: "token must be omitted when trustedPublishing is true",
2223
+ path: ["token"]
2224
+ });
2225
+ }
1723
2226
  }),
1724
2227
  zod.z.strictObject({
1725
2228
  registry: zod.z.literal("pypi").describe("Publishes the package to a PyPI-compatible registry."),
@@ -1797,10 +2300,29 @@ var sdkConfigV1OutputConfigSchema = zod.z.discriminatedUnion(
1797
2300
  [filesOutputSchema, zipOutputSchema, githubDeliverySchema],
1798
2301
  { error: 'output.delivery must be one of "files", "zip", or "github"' }
1799
2302
  );
1800
-
1801
- // src/sdk-config/v1/package.ts
1802
- var sdkConfigV1DependencySchema = dependencySchema;
1803
- var sdkConfigV1PackageConfigSchema = packageConfigSchema;
2303
+ var cliDistributionShape = {
2304
+ distribution: cliDistributionConfigSchema.optional().describe(
2305
+ "CLI release channels published by the generated release workflow; credentials are GitHub Actions secret names."
2306
+ )
2307
+ };
2308
+ function rejectDistributionWithoutGithub(output, context) {
2309
+ if (output.distribution !== void 0) {
2310
+ context.addIssue({
2311
+ code: "custom",
2312
+ message: CLI_DISTRIBUTION_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2313
+ path: ["distribution"]
2314
+ });
2315
+ }
2316
+ }
2317
+ var sdkConfigV1CliOutputConfigSchema = zod.z.discriminatedUnion(
2318
+ "delivery",
2319
+ [
2320
+ filesOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2321
+ zipOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2322
+ githubDeliverySchema.extend(cliDistributionShape)
2323
+ ],
2324
+ { error: 'output.delivery must be one of "files", "zip", or "github"' }
2325
+ );
1804
2326
  var sdkConfigV1ReplayConfigSchema = zod.z.strictObject({
1805
2327
  enabled: zod.z.boolean().describe("Whether regeneration reapplies customer-authored repository changes.")
1806
2328
  });
@@ -1877,10 +2399,6 @@ var sdkConfigV1SourceConfigSchema = zod.z.strictObject({
1877
2399
  seenIds.add(id);
1878
2400
  });
1879
2401
  });
1880
- var cliGenerationConfigSchema = zod.z.strictObject({
1881
- paginationParameters: zod.z.array(nonEmptyStringSchema).optional().describe("Request parameter names treated as pagination controls by the CLI."),
1882
- skills: zod.z.boolean().optional().describe("Whether the generated CLI includes skills that teach AI agents to invoke commands.")
1883
- });
1884
2402
  var csharpGenerationConfigSchema = zod.z.strictObject({
1885
2403
  useOptionalWrapper: zod.z.boolean().optional().describe("Whether optional values use an explicit Optional wrapper."),
1886
2404
  simplifyObjectDictionaries: zod.z.boolean().optional().describe("Whether object schemas with arbitrary values use simplified dictionary types."),
@@ -2133,7 +2651,10 @@ var sdkConfigV1TargetSchema = zod.z.discriminatedUnion("language", [
2133
2651
  zod.z.strictObject({
2134
2652
  language: zod.z.literal("cli").describe("Generates a command-line interface."),
2135
2653
  generation: sdkConfigV1GenerationConfigOverrideSchema.extend(cliGenerationConfigSchema.shape).optional().describe("Common and CLI-specific generation settings for this target."),
2136
- ...targetOverrideShape
2654
+ ...targetOverrideShape,
2655
+ output: sdkConfigV1CliOutputConfigSchema.optional().describe(
2656
+ "Output configuration, including optional CLI distribution channels, that replaces the root output for this target."
2657
+ )
2137
2658
  }),
2138
2659
  zod.z.strictObject({
2139
2660
  language: zod.z.literal("mcp").describe("Generates an MCP server."),
@@ -2150,7 +2671,7 @@ var sdkConfigV1TargetSchema = zod.z.discriminatedUnion("language", [
2150
2671
  // src/sdk-config/v1/sdk-config-v1.ts
2151
2672
  var SDK_CONFIG_V1_SCHEMA_VERSION = "sdk-config/v1";
2152
2673
  var publishRegistryLanguages = {
2153
- npm: ["typescript", "mcp"],
2674
+ npm: ["typescript", "mcp", "cli"],
2154
2675
  pypi: ["python"],
2155
2676
  maven: ["java", "kotlin"],
2156
2677
  nuget: ["csharp"],
@@ -2227,6 +2748,13 @@ function validateTargetPublishing(target, targetIndex, globalPackage, globalOutp
2227
2748
  });
2228
2749
  return;
2229
2750
  }
2751
+ if (target.language === "cli" && output.delivery !== "github") {
2752
+ context.addIssue({
2753
+ code: "custom",
2754
+ message: CLI_PUBLISH_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2755
+ path: target.output ? ["targets", targetIndex, "output", "delivery"] : ["output", "delivery"]
2756
+ });
2757
+ }
2230
2758
  validatePublishingIdentity(
2231
2759
  { ...globalPackage, ...target.package },
2232
2760
  registry,
@@ -2339,16 +2867,28 @@ function mapFernConfigToSdkConfigV1(input) {
2339
2867
  package: outputPackage,
2340
2868
  generation: outputGeneration
2341
2869
  }, index) => {
2870
+ const distribution = applyCliDistribution(output, invocation.cliDistribution, index);
2871
+ invocation.unsupportedFields.push(...distribution.diagnostics);
2342
2872
  const target = {
2343
2873
  language,
2344
- output,
2874
+ output: distribution.output,
2345
2875
  ...optional("sdkName", generator.sdkName),
2346
2876
  ...optional("sdkVersion", generator.sdkVersion),
2347
2877
  ...optional("client", clients.targetOverrides[index]),
2348
2878
  ...optional("docs", docs.targetOverrides[index])
2349
2879
  };
2350
- if (Object.keys(invocation.package).length > 0 || outputPackage || generator.package) {
2351
- target.package = { ...invocation.package, ...outputPackage, ...generator.package };
2880
+ const targetPackage = { ...invocation.package, ...outputPackage, ...generator.package };
2881
+ invocation.unsupportedFields.push(
2882
+ ...resolveTargetPackage(
2883
+ targetPackage,
2884
+ invocation.packageFallbacks,
2885
+ generator,
2886
+ output.delivery,
2887
+ index
2888
+ )
2889
+ );
2890
+ if (Object.keys(targetPackage).length > 0 || outputPackage || generator.package) {
2891
+ target.package = targetPackage;
2352
2892
  }
2353
2893
  const targetGeneration = {
2354
2894
  ...generations.targetOverrides[index],
@@ -2530,10 +3070,14 @@ function mapInvocation(generator, language, activeLanguages, index) {
2530
3070
  ...optional("smartCasingDigitWordBoundary", smartCasingDigitWordBoundary)
2531
3071
  };
2532
3072
  }
2533
- const targetGeneration = mapLanguageConfig(language, config, state, packageConfig, [
2534
- ...prefix,
2535
- "config"
2536
- ]);
3073
+ const targetGeneration = mapLanguageConfig(
3074
+ language,
3075
+ config,
3076
+ state,
3077
+ packageConfig,
3078
+ [...prefix, "config"],
3079
+ index
3080
+ );
2537
3081
  mapPublishMetadata(generator.publishMetadata, packageConfig);
2538
3082
  if (generator.keywords?.length) {
2539
3083
  generation.reservedKeywords = [...generator.keywords];
@@ -2550,12 +3094,22 @@ function mapInvocation(generator, language, activeLanguages, index) {
2550
3094
  }
2551
3095
  const docs = mapReadme(generator.readme, language, activeLanguages, state, [...prefix, "readme"]);
2552
3096
  const unsupportedFields = [
3097
+ ...state.valueDiagnostics ?? [],
2553
3098
  ...collectUnsupported(config, [...prefix, "config"], state),
2554
3099
  ...settings ? collectUnsupported(settings, [...prefix, "settings"], state) : [],
2555
3100
  ...isObject(generator.readme) ? collectUnsupported(generator.readme, [...prefix, "readme"], state) : [],
2556
3101
  ...unsupportedResolvedFields(generator, index, apiWideIdempotency !== void 0)
2557
3102
  ];
2558
- return { client, docs, generation, package: packageConfig, targetGeneration, unsupportedFields };
3103
+ return {
3104
+ client,
3105
+ docs,
3106
+ generation,
3107
+ package: packageConfig,
3108
+ packageFallbacks: state.packageFallbacks ?? [],
3109
+ ...optional("cliDistribution", state.cliDistribution),
3110
+ targetGeneration,
3111
+ unsupportedFields
3112
+ };
2559
3113
  }
2560
3114
  function unsupportedResolvedFields(generator, index, idempotencyMapped) {
2561
3115
  const values = [
@@ -2745,6 +3299,7 @@ function mapCommonConfig(language, config, state, client, generation, packageCon
2745
3299
  const packagePath = takeString(config, ["packagePath"], state, basePath);
2746
3300
  if (packagePath !== void 0) generation.layout = { packagePath };
2747
3301
  mapDependencies(config, state, packageConfig, basePath);
3302
+ mapPeerDependenciesMeta(config, state, packageConfig, basePath);
2748
3303
  }
2749
3304
  function mapTypescriptStreams(config, state, basePath) {
2750
3305
  const responseType = takeEnum(config, ["streamType"], ["wrapper", "web"], state, basePath);
@@ -2758,7 +3313,7 @@ function mapTypescriptStreams(config, state, basePath) {
2758
3313
  if (responseType === void 0 && fileResponseType === void 0) return void 0;
2759
3314
  return { enabled: true, ...compact({ responseType, fileResponseType }) };
2760
3315
  }
2761
- function mapLanguageConfig(language, config, state, packageConfig, basePath) {
3316
+ function mapLanguageConfig(language, config, state, packageConfig, basePath, targetIndex) {
2762
3317
  switch (language) {
2763
3318
  case "typescript":
2764
3319
  return mapTypescript(config, state, packageConfig, basePath);
@@ -2785,7 +3340,7 @@ function mapLanguageConfig(language, config, state, packageConfig, basePath) {
2785
3340
  case "swift":
2786
3341
  return mapSwift(config, state, basePath);
2787
3342
  case "cli":
2788
- return mapCli(config, state, packageConfig, basePath);
3343
+ return mapCli(config, state, packageConfig, basePath, targetIndex);
2789
3344
  case "terraform":
2790
3345
  return mapTerraform(config, state, packageConfig, basePath);
2791
3346
  }
@@ -2802,6 +3357,7 @@ function mapTypescript(config, state, packageConfig, basePath) {
2802
3357
  const packageManagerAtIndex = packageJsonPackageManager ? packageJsonPackageManager.indexOf("@", packageJsonPackageManager.startsWith("@") ? 1 : 0) : -1;
2803
3358
  const packageManagerVersionPart = packageManagerAtIndex >= 0 ? packageJsonPackageManager?.slice(packageManagerAtIndex + 1).split("+")[0] : void 0;
2804
3359
  const packageManagerVersion = packageManagerVersionPart || void 0;
3360
+ if (packageJsonManifest) liftPackageJsonDependencies(packageJsonManifest, state, packageConfig);
2805
3361
  const serdeLayer = takeBoolean(config, ["serdeLayer"], state, basePath);
2806
3362
  const noSerdeLayer = takeBoolean(config, ["noSerdeLayer"], state, basePath);
2807
3363
  const fetchSupport = takeEnum(config, ["fetchSupport"], ["native"], state, basePath);
@@ -2971,6 +3527,7 @@ function mapRust(config, state, packageConfig, basePath) {
2971
3527
  const description = takeString(config, ["packageDescription"], state, basePath);
2972
3528
  const documentationUrl = takeString(config, ["packageDocumentation"], state, basePath);
2973
3529
  Object.assign(packageConfig, compact({ packageName, repository, description, documentationUrl }));
3530
+ mapLicenseFallback(config, ["packageLicense"], state, basePath);
2974
3531
  return compact({
2975
3532
  dateTimeType: takeEnum(config, ["dateTimeType"], ["offset", "utc"], state, basePath),
2976
3533
  capitalizeInitialisms: takeBoolean(config, ["capitalizeInitialisms"], state, basePath),
@@ -2984,7 +3541,7 @@ function mapSwift(config, state, basePath) {
2984
3541
  nullableAsOptional: takeBoolean(config, ["nullableAsOptional"], state, basePath)
2985
3542
  });
2986
3543
  }
2987
- function mapCli(config, state, packageConfig, basePath) {
3544
+ function mapCli(config, state, packageConfig, basePath, targetIndex) {
2988
3545
  const identity = takeObject(config, ["packageIdentity"], state, basePath);
2989
3546
  if (identity) {
2990
3547
  Object.assign(
@@ -2995,10 +3552,13 @@ function mapCli(config, state, packageConfig, basePath) {
2995
3552
  description: takeString(identity.value, ["description"], state, identity.path)
2996
3553
  })
2997
3554
  );
3555
+ mapCliPackageIdentity(identity, state, targetIndex);
2998
3556
  }
3557
+ mapCliDistribution(config, state, basePath, targetIndex);
2999
3558
  return compact({
3000
3559
  paginationParameters: takeStringArray(config, ["paginationParameters"], state, basePath),
3001
- skills: takeBoolean(config, ["skills"], state, basePath)
3560
+ skills: takeBoolean(config, ["skills"], state, basePath),
3561
+ ...mapCliGeneration(config, state, basePath, targetIndex)
3002
3562
  });
3003
3563
  }
3004
3564
  function mapTerraform(config, state, packageConfig, basePath) {
@@ -3082,6 +3642,48 @@ function mapDependencies(config, state, packageConfig, basePath) {
3082
3642
  if (dependencies.length) packageConfig[field] = dependencies;
3083
3643
  }
3084
3644
  }
3645
+ function liftPackageJsonDependencies(manifest, state, packageConfig) {
3646
+ for (const [field, target] of [
3647
+ ["dependencies", "extraDependencies"],
3648
+ ["devDependencies", "extraDevDependencies"],
3649
+ ["peerDependencies", "extraPeerDependencies"]
3650
+ ]) {
3651
+ const located = takeObject(manifest.value, [field], state, manifest.path);
3652
+ if (!located) continue;
3653
+ const lifted = Object.entries(located.value).flatMap(
3654
+ ([name, dependency]) => mapDependency(name, dependency, state, [...located.path, name])
3655
+ );
3656
+ if (lifted.length) packageConfig[target] = overrideByName(packageConfig[target] ?? [], lifted);
3657
+ }
3658
+ const meta = takeObject(manifest.value, ["peerDependenciesMeta"], state, manifest.path);
3659
+ if (!meta) return;
3660
+ const entries = peerDependenciesMetaEntries(meta, state);
3661
+ if (entries.length) {
3662
+ packageConfig.extraPeerDependenciesMeta = {
3663
+ ...packageConfig.extraPeerDependenciesMeta,
3664
+ ...Object.fromEntries(entries)
3665
+ };
3666
+ }
3667
+ }
3668
+ function overrideByName(existing, overrides) {
3669
+ const byName = new Map(existing.map((dependency) => [dependency.name, dependency]));
3670
+ overrides.forEach((dependency) => byName.set(dependency.name, dependency));
3671
+ return [...byName.values()];
3672
+ }
3673
+ function mapPeerDependenciesMeta(config, state, packageConfig, basePath) {
3674
+ const located = takeObject(config, ["extraPeerDependenciesMeta"], state, basePath);
3675
+ if (!located) return;
3676
+ const entries = peerDependenciesMetaEntries(located, state);
3677
+ if (entries.length) packageConfig.extraPeerDependenciesMeta = Object.fromEntries(entries);
3678
+ }
3679
+ function peerDependenciesMetaEntries(located, state) {
3680
+ return Object.entries(located.value).flatMap(([name, value]) => {
3681
+ const parsed = jsonObjectSchema.safeParse(value);
3682
+ if (!parsed.success) return [];
3683
+ consume(state, [...located.path, name]);
3684
+ return [[name, parsed.data]];
3685
+ });
3686
+ }
3085
3687
  function mapDependency(name, value, state, path) {
3086
3688
  if (typeof value === "string" && value) {
3087
3689
  consume(state, path);
@@ -3089,13 +3691,7 @@ function mapDependency(name, value, state, path) {
3089
3691
  }
3090
3692
  if (!isObject(value)) return [];
3091
3693
  const version = takeString(value, ["version"], state, path);
3092
- const gitUrl = takeString(value, ["git"], state, path);
3093
- const localPath = takeString(value, ["path"], state, path);
3094
- const source = gitUrl ? {
3095
- type: "git",
3096
- url: gitUrl,
3097
- ...optional("ref", takeString(value, ["ref"], state, path))
3098
- } : localPath ? { type: "path", path: localPath } : void 0;
3694
+ const source = takeDependencySource(value, state, path);
3099
3695
  if (!version && !source) return [];
3100
3696
  return [
3101
3697
  {
@@ -3111,6 +3707,17 @@ function mapDependency(name, value, state, path) {
3111
3707
  }
3112
3708
  ];
3113
3709
  }
3710
+ function takeDependencySource(value, state, path) {
3711
+ const gitUrl = takeString(value, ["git"], state, path);
3712
+ if (gitUrl) {
3713
+ const ref = takeString(value, ["ref", "rev", "branch"], state, path);
3714
+ return { type: "git", url: gitUrl, ...optional("ref", ref) };
3715
+ }
3716
+ const localPath = takeString(value, ["path"], state, path);
3717
+ if (localPath) return { type: "path", path: localPath };
3718
+ const registry = takeString(value, ["registry"], state, path);
3719
+ return registry ? { type: "registry", registry } : void 0;
3720
+ }
3114
3721
  function takeCustomSections(value, language, activeLanguages, state, basePath) {
3115
3722
  const located = locate(value, ["customSections"], basePath);
3116
3723
  if (!located || !Array.isArray(located.value)) return void 0;
@@ -3299,6 +3906,15 @@ var compatibilityConfigSchema = zod.z.strictObject({
3299
3906
  legacyInput: legacyInputSchema.optional().describe("Original producer input retained only for migration debugging."),
3300
3907
  unsupportedFields: zod.z.array(unsupportedFieldSchema).optional().describe("Legacy fields that could not be represented in normalized configuration.")
3301
3908
  });
3909
+
3910
+ // src/sdk-config-ir/v1/diagnostics.ts
3911
+ function getSdkConfigIrV1Diagnostics(config) {
3912
+ if (config.target.language !== "cli") {
3913
+ return [];
3914
+ }
3915
+ const diagnostic = cliDistributionModeDiagnostic(config.output, ["output"]);
3916
+ return diagnostic ? [diagnostic] : [];
3917
+ }
3302
3918
  var generationAssetSchema = zod.z.discriminatedUnion("type", [
3303
3919
  zod.z.strictObject({
3304
3920
  type: zod.z.literal("path").describe("Loads the generation asset from a relative path."),
@@ -3601,6 +4217,12 @@ var githubOutputSchema2 = zod.z.strictObject({
3601
4217
  /** Automatically merge the GitHub publishing PR. Defaults to false. */
3602
4218
  autoMerge: zod.z.boolean().default(false).describe("Whether the GitHub publisher automatically merges its pull request.")
3603
4219
  });
4220
+ var distributionShape = {
4221
+ /** Valid only for `cli` targets with GitHub delivery; secret names only, never values. */
4222
+ distribution: cliDistributionConfigSchema.optional().describe(
4223
+ "CLI release channels published by the generated release workflow; credentials are GitHub Actions secret names."
4224
+ )
4225
+ };
3604
4226
  var credentialResolutionShape = {
3605
4227
  /** Where output credential references are resolved. */
3606
4228
  credentialResolution: credentialResolutionSchema.default("refs-only").describe("Where output credential references are resolved.")
@@ -3609,18 +4231,21 @@ var filesOutputSchema2 = zod.z.strictObject({
3609
4231
  delivery: zod.z.literal("files").describe("Writes the generated SDK to a directory."),
3610
4232
  path: nonEmptyStringSchema.optional().describe("The destination directory for generated files."),
3611
4233
  publish: publishConfigSchema.optional().describe("Optional package registry publication."),
4234
+ ...distributionShape,
3612
4235
  ...credentialResolutionShape
3613
4236
  });
3614
4237
  var zipOutputSchema2 = zod.z.strictObject({
3615
4238
  delivery: zod.z.literal("zip").describe("Packages the generated SDK as a ZIP archive."),
3616
4239
  fileName: nonEmptyStringSchema.optional().describe("The generated ZIP archive file name."),
3617
4240
  publish: publishConfigSchema.optional().describe("Optional package registry publication."),
4241
+ ...distributionShape,
3618
4242
  ...credentialResolutionShape
3619
4243
  });
3620
4244
  var githubDeliverySchema2 = zod.z.strictObject({
3621
4245
  delivery: zod.z.literal("github").describe("Delivers the generated SDK to GitHub."),
3622
4246
  github: githubOutputSchema2.describe("GitHub repository delivery settings."),
3623
4247
  publish: publishConfigSchema.optional().describe("Optional package registry publication."),
4248
+ ...distributionShape,
3624
4249
  ...credentialResolutionShape
3625
4250
  });
3626
4251
  var outputConfigSchema = zod.z.discriminatedUnion(
@@ -3705,7 +4330,7 @@ var targetConfigSchema = zod.z.strictObject({
3705
4330
  // src/sdk-config-ir/v1/sdk-config-ir-v1.ts
3706
4331
  var SDK_CONFIG_IR_V1_SCHEMA_VERSION = "sdk-config-ir/v1";
3707
4332
  var publishRegistryLanguages2 = {
3708
- npm: ["typescript", "mcp"],
4333
+ npm: ["typescript", "mcp", "cli"],
3709
4334
  pypi: ["python"],
3710
4335
  maven: ["java", "kotlin"],
3711
4336
  nuget: ["csharp"],
@@ -3760,6 +4385,28 @@ function validatePublishingIdentity2(packageConfig, registry, context) {
3760
4385
  });
3761
4386
  }
3762
4387
  }
4388
+ function validateCliOutput(output, language, context) {
4389
+ if (output.distribution !== void 0 && language !== "cli") {
4390
+ context.addIssue({
4391
+ code: "custom",
4392
+ message: `output.distribution is supported only for target language "cli", not "${language}"`,
4393
+ path: ["output", "distribution"]
4394
+ });
4395
+ } else if (output.distribution !== void 0 && output.delivery !== "github") {
4396
+ context.addIssue({
4397
+ code: "custom",
4398
+ message: CLI_DISTRIBUTION_REQUIRES_GITHUB_DELIVERY_MESSAGE,
4399
+ path: ["output", "distribution"]
4400
+ });
4401
+ }
4402
+ if (language === "cli" && output.publish && output.delivery !== "github") {
4403
+ context.addIssue({
4404
+ code: "custom",
4405
+ message: CLI_PUBLISH_REQUIRES_GITHUB_DELIVERY_MESSAGE,
4406
+ path: ["output", "publish"]
4407
+ });
4408
+ }
4409
+ }
3763
4410
  var sdkConfigIrV1Schema = zod.z.strictObject({
3764
4411
  schemaVersion: zod.z.literal(SDK_CONFIG_IR_V1_SCHEMA_VERSION).describe("The version of the normalized SDK Config IR schema."),
3765
4412
  source: sourceConfigSchema.describe("Materialized API descriptions consumed by generation."),
@@ -3821,6 +4468,7 @@ var sdkConfigIrV1Schema = zod.z.strictObject({
3821
4468
  });
3822
4469
  }
3823
4470
  }
4471
+ validateCliOutput(output, target.language, context);
3824
4472
  if (compatibility?.legacyInput) {
3825
4473
  const expectedKind = target.sourceOrigin === "postman" ? "postman-build-parameters" : "fern-generator-invocation";
3826
4474
  if (compatibility.legacyInput.kind !== expectedKind) {
@@ -3860,13 +4508,19 @@ function parseSdkConfigIrV1ForConsumption(value) {
3860
4508
  return parseSdkConfigIrV1(stripUnknownProperties(value, sdkConfigIrV1InputJsonSchema));
3861
4509
  }
3862
4510
 
4511
+ exports.CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE = CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE;
3863
4512
  exports.FernConfigMappingError = FernConfigMappingError;
3864
4513
  exports.SDK_CONFIG_IR_V1_SCHEMA_VERSION = SDK_CONFIG_IR_V1_SCHEMA_VERSION;
4514
+ exports.SDK_CONFIG_V1_CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE = CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE;
3865
4515
  exports.SDK_CONFIG_V1_SCHEMA_VERSION = SDK_CONFIG_V1_SCHEMA_VERSION;
3866
4516
  exports.apiConfigSchema = apiConfigSchema;
3867
4517
  exports.apiImportSettingsSchema = apiImportSettingsSchema;
3868
4518
  exports.authConfigSchema = authConfigSchema;
3869
4519
  exports.authSchemeSchema = authSchemeSchema;
4520
+ exports.cliDistributionConfigSchema = cliDistributionConfigSchema;
4521
+ exports.cliDistributionGithubAppSchema = cliDistributionGithubAppSchema;
4522
+ exports.cliDistributionHomebrewSchema = cliDistributionHomebrewSchema;
4523
+ exports.cliDistributionScoopSchema = cliDistributionScoopSchema;
3870
4524
  exports.cliGenerationConfigSchema = cliGenerationConfigSchema;
3871
4525
  exports.clientConfigOverrideSchema = clientConfigOverrideSchema;
3872
4526
  exports.clientConfigSchema = clientConfigSchema;
@@ -3878,6 +4532,9 @@ exports.dependencySchema = dependencySchema;
3878
4532
  exports.docsConfigSchema = docsConfigSchema;
3879
4533
  exports.exactSemverSchema = exactSemverSchema;
3880
4534
  exports.generationConfigSchema = generationConfigSchema;
4535
+ exports.getSdkConfigIrV1Diagnostics = getSdkConfigIrV1Diagnostics;
4536
+ exports.getSdkConfigV1Diagnostics = getSdkConfigV1Diagnostics;
4537
+ exports.githubActionsSecretNameSchema = githubActionsSecretNameSchema;
3881
4538
  exports.goGenerationConfigSchema = goGenerationConfigSchema;
3882
4539
  exports.goModulePathSchema = goModulePathSchema;
3883
4540
  exports.javaGenerationConfigSchema = javaGenerationConfigSchema;
@@ -3911,7 +4568,12 @@ exports.sdkConfigIrV1Schema = sdkConfigIrV1Schema;
3911
4568
  exports.sdkConfigV1ApiConfigSchema = sdkConfigV1ApiConfigSchema;
3912
4569
  exports.sdkConfigV1AuthConfigSchema = sdkConfigV1AuthConfigSchema;
3913
4570
  exports.sdkConfigV1AuthSchemeSchema = sdkConfigV1AuthSchemeSchema;
4571
+ exports.sdkConfigV1CliDistributionConfigSchema = cliDistributionConfigSchema;
4572
+ exports.sdkConfigV1CliDistributionGithubAppSchema = cliDistributionGithubAppSchema;
4573
+ exports.sdkConfigV1CliDistributionHomebrewSchema = cliDistributionHomebrewSchema;
4574
+ exports.sdkConfigV1CliDistributionScoopSchema = cliDistributionScoopSchema;
3914
4575
  exports.sdkConfigV1CliGenerationConfigSchema = cliGenerationConfigSchema;
4576
+ exports.sdkConfigV1CliOutputConfigSchema = sdkConfigV1CliOutputConfigSchema;
3915
4577
  exports.sdkConfigV1ClientConfigOverrideSchema = sdkConfigV1ClientConfigOverrideSchema;
3916
4578
  exports.sdkConfigV1ClientConfigSchema = sdkConfigV1ClientConfigSchema;
3917
4579
  exports.sdkConfigV1ComposerPackageNameSchema = composerPackageNameSchema;
@@ -3921,6 +4583,7 @@ exports.sdkConfigV1DocsConfigSchema = sdkConfigV1DocsConfigSchema;
3921
4583
  exports.sdkConfigV1ExactSemverSchema = exactSemverSchema;
3922
4584
  exports.sdkConfigV1GenerationConfigOverrideSchema = sdkConfigV1GenerationConfigOverrideSchema;
3923
4585
  exports.sdkConfigV1GenerationConfigSchema = sdkConfigV1GenerationConfigSchema;
4586
+ exports.sdkConfigV1GithubActionsSecretNameSchema = githubActionsSecretNameSchema;
3924
4587
  exports.sdkConfigV1GoGenerationConfigSchema = goGenerationConfigSchema;
3925
4588
  exports.sdkConfigV1GoModulePathSchema = goModulePathSchema;
3926
4589
  exports.sdkConfigV1JavaGenerationConfigSchema = javaGenerationConfigSchema;