@postman/sdk-config 0.9.0 → 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 +776 -44
  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 +762 -45
  7. package/dist/index.js.map +1 -1
  8. package/dist/sdk-config/index.cjs +728 -44
  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 +721 -45
  13. package/dist/sdk-config/index.js.map +1 -1
  14. package/dist/sdk-config/v1/index.cjs +728 -44
  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 +721 -45
  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
@@ -27,7 +27,7 @@ var jsonValueSchema = z.lazy(
27
27
  z.record(z.string(), jsonValueSchema)
28
28
  ])
29
29
  );
30
- z.record(z.string(), jsonValueSchema);
30
+ var jsonObjectSchema = z.record(z.string(), jsonValueSchema);
31
31
  var hashAlgorithmSchema = z.enum(["sha1", "sha256", "sha384", "sha512"]);
32
32
  var encodingSchema = z.enum(["base64", "hex"]);
33
33
  var payloadComponentSchema = z.enum(["body", "timestamp", "notification-url", "message-id"]);
@@ -125,13 +125,21 @@ var oauthScopeSchema = z.strictObject({
125
125
  name: nonEmptyStringSchema.describe("The OAuth scope value requested from the provider."),
126
126
  description: z.string().optional().describe("A description of the OAuth scope included in generated SDK documentation.")
127
127
  });
128
+ var publicClientIdSchema = nonEmptyStringSchema.refine((value) => value.trim() === value, {
129
+ message: "must not have leading or trailing whitespace"
130
+ }).refine((value) => !value.includes("${"), {
131
+ message: "must be a literal public client ID, not an environment expression"
132
+ });
128
133
  var oauthFlowSchema = z.discriminatedUnion("type", [
129
134
  z.strictObject({
130
135
  type: z.literal("authorization-code").describe("Uses the OAuth authorization code flow."),
131
136
  authorizationUrl: nonEmptyStringSchema.describe("The URL used to authorize the client."),
132
137
  tokenUrl: nonEmptyStringSchema.describe("The URL used to exchange a code for tokens."),
133
138
  refreshUrl: nonEmptyStringSchema.optional().describe("The URL used to refresh access tokens."),
134
- scopes: z.array(oauthScopeSchema).optional().describe("The scopes supported by this flow.")
139
+ scopes: z.array(oauthScopeSchema).optional().describe("The scopes supported by this flow."),
140
+ clientId: publicClientIdSchema.optional().describe(
141
+ "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."
142
+ )
135
143
  }),
136
144
  z.strictObject({
137
145
  type: z.literal("client-credentials").describe("Uses the OAuth client credentials flow."),
@@ -447,8 +455,102 @@ var packageConfigSchema = z.strictObject({
447
455
  projectUrls: z.array(projectUrlSchema).optional().describe("Labeled project links for package metadata."),
448
456
  extraDependencies: z.array(dependencySchema).optional().describe("Additional runtime dependencies added to the generated package."),
449
457
  extraDevDependencies: z.array(dependencySchema).optional().describe("Additional development dependencies added to the generated package."),
450
- extraPeerDependencies: z.array(dependencySchema).optional().describe("Additional peer dependencies added to the generated package.")
458
+ extraPeerDependencies: z.array(dependencySchema).optional().describe("Additional peer dependencies added to the generated package."),
459
+ extraPeerDependenciesMeta: z.record(nonEmptyStringSchema, jsonObjectSchema).optional().describe(
460
+ "npm peerDependenciesMeta entries keyed by peer dependency name, such as { optional: true }."
461
+ )
462
+ });
463
+ var GITHUB_ACTIONS_SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
464
+ var GITHUB_REPOSITORY_SLUG_PATTERN = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
465
+ var HOMEBREW_FORMULA_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
466
+ var githubActionsSecretNameSchema = z.string({ error: "must be the name of a GitHub Actions secret" }).regex(GITHUB_ACTIONS_SECRET_NAME_PATTERN, {
467
+ 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."
468
+ }).refine((value) => value !== "GITHUB_TOKEN", {
469
+ 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."
470
+ });
471
+ var githubRepositorySlugSchema = z.string({ error: 'must be a GitHub repository in "<owner>/<repo>" form' }).regex(GITHUB_REPOSITORY_SLUG_PATTERN, {
472
+ error: 'must be a GitHub repository in "<owner>/<repo>" form, for example "acme/homebrew-tap"'
473
+ });
474
+ var homebrewFormulaNameSchema = z.string({ error: "must be a Homebrew formula name" }).regex(HOMEBREW_FORMULA_NAME_PATTERN, {
475
+ error: "must be a Homebrew formula name: start with a lowercase letter and contain only a-z, 0-9, or -"
476
+ });
477
+ var cliDistributionGithubAppSchema = z.strictObject({
478
+ appIdSecretName: githubActionsSecretNameSchema.describe(
479
+ "The name of the GitHub Actions secret holding the GitHub App ID or client ID."
480
+ ),
481
+ privateKeySecretName: githubActionsSecretNameSchema.describe(
482
+ "The name of the GitHub Actions secret holding the GitHub App private key in PEM form."
483
+ )
484
+ });
485
+ 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.";
486
+ var cliDistributionHomebrewSchema = z.strictObject({
487
+ tap: githubRepositorySlugSchema.describe(
488
+ 'The Homebrew tap repository in "<owner>/<repo>" form that receives the formula.'
489
+ ),
490
+ formula: homebrewFormulaNameSchema.optional().describe("The Homebrew formula name; the generator defaults it to the CLI binary name."),
491
+ tokenSecretName: githubActionsSecretNameSchema.optional().describe(channelTokenSecretNameDescription)
492
+ });
493
+ var cliDistributionScoopSchema = z.strictObject({
494
+ bucket: githubRepositorySlugSchema.describe(
495
+ 'The Scoop bucket repository in "<owner>/<repo>" form that receives the manifest.'
496
+ ),
497
+ tokenSecretName: githubActionsSecretNameSchema.optional().describe(channelTokenSecretNameDescription)
451
498
  });
499
+ var cliDistributionConfigSchema = z.strictObject({
500
+ githubApp: cliDistributionGithubAppSchema.optional().describe(
501
+ "A GitHub App used to mint short-lived tokens for every channel without its own tokenSecretName."
502
+ ),
503
+ homebrew: cliDistributionHomebrewSchema.optional().describe("Publishes a Homebrew formula to a tap repository on each tagged release."),
504
+ scoop: cliDistributionScoopSchema.optional().describe("Publishes a Scoop manifest to a bucket repository on each tagged release.")
505
+ }).superRefine((distribution, context) => {
506
+ if (distribution.homebrew !== void 0 || distribution.scoop !== void 0) {
507
+ return;
508
+ }
509
+ if (distribution.githubApp !== void 0) {
510
+ context.addIssue({
511
+ code: "custom",
512
+ message: "githubApp requires at least one distribution channel: homebrew or scoop",
513
+ path: ["githubApp"]
514
+ });
515
+ return;
516
+ }
517
+ context.addIssue({
518
+ code: "custom",
519
+ message: "distribution must configure at least one channel: homebrew or scoop"
520
+ });
521
+ });
522
+ 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.';
523
+ 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.';
524
+ var CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE = "CLI_DISTRIBUTION_NON_RELEASE_MODE";
525
+ var nonReleaseGithubModes = /* @__PURE__ */ new Set(["pull-request", "push", "commit"]);
526
+ function cliDistributionModeDiagnostic(output, outputPath) {
527
+ const mode = output?.github?.mode;
528
+ if (output?.distribution === void 0 || mode === void 0 || !nonReleaseGithubModes.has(mode)) {
529
+ return void 0;
530
+ }
531
+ return {
532
+ code: CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE,
533
+ severity: "warning",
534
+ path: [...outputPath, "github", "mode"],
535
+ 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.`,
536
+ suggestedAction: 'Use mode "release" or "commit-and-release", or push a version tag after merging generated changes.'
537
+ };
538
+ }
539
+
540
+ // src/sdk-config/v1/diagnostics.ts
541
+ function getSdkConfigV1Diagnostics(config) {
542
+ return config.targets.flatMap((target, targetIndex) => {
543
+ if (target.language !== "cli") {
544
+ return [];
545
+ }
546
+ const diagnostic = cliDistributionModeDiagnostic(target.output, [
547
+ "targets",
548
+ targetIndex,
549
+ "output"
550
+ ]);
551
+ return diagnostic ? [diagnostic] : [];
552
+ });
553
+ }
452
554
  var httpMethodSchema = z.enum([
453
555
  "GET",
454
556
  "POST",
@@ -653,6 +755,17 @@ function stringValue(value) {
653
755
  function stringArrayValue(value) {
654
756
  return Array.isArray(value) && value.every((item) => typeof item === "string" && item.length > 0) ? value : void 0;
655
757
  }
758
+ var canonicalLicenseTypes = {
759
+ mit: "MIT",
760
+ apache: "APACHE",
761
+ "apache-2.0": "APACHE",
762
+ "gpl-3.0": "GPL3",
763
+ "gpl-3.0-only": "GPL3",
764
+ unlicensed: "UNLICENSED"
765
+ };
766
+ function canonicalLicenseType(value) {
767
+ return canonicalLicenseTypes[value.trim().toLowerCase()];
768
+ }
656
769
  function stableJson(value) {
657
770
  return JSON.stringify(sortKeys(value));
658
771
  }
@@ -663,6 +776,280 @@ function sortKeys(value) {
663
776
  Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, sortKeys(child)])
664
777
  );
665
778
  }
779
+ var ALPHANUMERIC_PATTERN = /[A-Za-z0-9]/;
780
+ var ROOT_GROUP_PATTERN = /^[a-z][a-z0-9_-]*$/;
781
+ var KEBAB_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
782
+ var DOTTED_COMMAND_PATH_PATTERN = /^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/;
783
+ var FIELD_NAME_PATTERN = /^[A-Za-z0-9_.-]+$/;
784
+ var RESERVED_USER_AGENT_SUFFIX_FLAGS = /* @__PURE__ */ new Set([
785
+ "params",
786
+ "output",
787
+ "json",
788
+ "format",
789
+ "dry-run",
790
+ "base-url",
791
+ "page-all",
792
+ "page-limit",
793
+ "page-delay",
794
+ "no-pager",
795
+ "no-extract",
796
+ "no-retry",
797
+ "no-stream",
798
+ "quiet",
799
+ "query",
800
+ "help",
801
+ "debug",
802
+ "schema"
803
+ ]);
804
+ var RESERVED_PROFILES_COMMAND_NAMES = /* @__PURE__ */ new Set([
805
+ "auth",
806
+ "completion",
807
+ "man",
808
+ "errors",
809
+ "generate-skills",
810
+ "help"
811
+ ]);
812
+ var binaryNameSchema = nonEmptyStringSchema.regex(ALPHANUMERIC_PATTERN, {
813
+ message: "binaryName must contain at least one ASCII letter or digit"
814
+ });
815
+ var rootGroupSchema = z.string().regex(ROOT_GROUP_PATTERN, {
816
+ message: "rootGroup must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores"
817
+ });
818
+ var userAgentSuffixFlagSchema = z.string().superRefine((value, context) => {
819
+ if (value.startsWith("-")) {
820
+ context.addIssue({
821
+ code: "custom",
822
+ message: 'userAgentSuffixFlag must be the long flag name without the leading "--"'
823
+ });
824
+ } else if (!KEBAB_NAME_PATTERN.test(value)) {
825
+ context.addIssue({
826
+ code: "custom",
827
+ message: "userAgentSuffixFlag must start with a lowercase letter and contain only lowercase letters, digits, and hyphens"
828
+ });
829
+ } else if (RESERVED_USER_AGENT_SUFFIX_FLAGS.has(value)) {
830
+ context.addIssue({
831
+ code: "custom",
832
+ message: `userAgentSuffixFlag "${value}" collides with a built-in global flag`
833
+ });
834
+ }
835
+ });
836
+ var profilesCommandNameSchema = z.string().superRefine((value, context) => {
837
+ if (!KEBAB_NAME_PATTERN.test(value)) {
838
+ context.addIssue({
839
+ code: "custom",
840
+ message: "profiles.commandName must start with a lowercase letter and contain only lowercase letters, digits, and hyphens"
841
+ });
842
+ } else if (RESERVED_PROFILES_COMMAND_NAMES.has(value)) {
843
+ context.addIssue({
844
+ code: "custom",
845
+ message: `profiles.commandName "${value}" collides with a built-in command group`
846
+ });
847
+ }
848
+ });
849
+ function dottedCommandPathSchema(field) {
850
+ return z.string().regex(DOTTED_COMMAND_PATH_PATTERN, {
851
+ message: `${field} must be a dotted command path such as "iam.keys.create"`
852
+ });
853
+ }
854
+ function fieldNameMapSchema(field) {
855
+ const message = `${field} keys and values must be field names containing only [A-Za-z0-9_.-]`;
856
+ return z.record(z.string(), z.string().regex(FIELD_NAME_PATTERN, { message })).superRefine((value, context) => {
857
+ for (const key of Object.keys(value)) {
858
+ if (!FIELD_NAME_PATTERN.test(key)) {
859
+ context.addIssue({ code: "custom", message, path: [key] });
860
+ }
861
+ }
862
+ });
863
+ }
864
+ var profilesProvisionOperationSchema = z.strictObject({
865
+ operation: dottedCommandPathSchema("profiles.provisionOperation.operation").describe(
866
+ "The dotted command path of the operation that mints a profile credential."
867
+ ),
868
+ credential: fieldNameMapSchema("profiles.provisionOperation.credential").refine((value) => Object.keys(value).length > 0, {
869
+ message: "profiles.provisionOperation.credential must map at least one credential field"
870
+ }).describe("Maps each stored credential field to the response field that supplies it."),
871
+ revokeParameters: fieldNameMapSchema("profiles.provisionOperation.revokeParameters").optional().describe("Maps each revoke-operation parameter to the response field that supplies it.")
872
+ });
873
+ var profilesConfigSchema = z.strictObject({
874
+ enabled: z.boolean().describe("Whether the CLI emits profile commands and the global --profile flag."),
875
+ commandName: profilesCommandNameSchema.optional().describe('The profile command group name. The generator defaults to "profiles".'),
876
+ revokeOperation: dottedCommandPathSchema("profiles.revokeOperation").optional().describe('The dotted command path called by "profiles remove --revoke".'),
877
+ provisionOperation: profilesProvisionOperationSchema.optional().describe('The operation called by "profiles create --provision" and its response mapping.')
878
+ });
879
+ var cliGenerationConfigSchema = z.strictObject({
880
+ paginationParameters: z.array(nonEmptyStringSchema).optional().describe("Request parameter names treated as pagination controls by the CLI."),
881
+ skills: z.boolean().optional().describe("Whether the generated CLI includes skills that teach AI agents to invoke commands."),
882
+ binaryName: binaryNameSchema.optional().describe(
883
+ "The CLI executable name. The generator kebab-cases it and also uses it for the source directory and env-var prefix."
884
+ ),
885
+ customCommands: z.boolean().optional().describe("Whether hand-written command support is generated. The generator defaults to true."),
886
+ rootGroup: rootGroupSchema.optional().describe("A command group that every spec-derived command is nested under."),
887
+ profiles: profilesConfigSchema.optional().describe("Named profile command configuration."),
888
+ splitTypeCrates: z.boolean().optional().describe("Whether generated types are split into one crate per API behind a facade crate."),
889
+ userAgentSuffixFlag: userAgentSuffixFlagSchema.optional().describe('The long flag name, without "--", that appends a product token to the User-Agent.')
890
+ });
891
+
892
+ // src/sdk-config/v1/fern-config-mapper-cli.ts
893
+ var CLI_GENERATION_FIELDS = [
894
+ "binaryName",
895
+ "customCommands",
896
+ "rootGroup",
897
+ "profiles",
898
+ "splitTypeCrates",
899
+ "userAgentSuffixFlag"
900
+ ];
901
+ var PROFILES_FIELDS = ["enabled", "commandName", "revokeOperation"];
902
+ var PROVISION_OPERATION_FIELDS = ["operation", "credential", "revokeParameters"];
903
+ function mapCliGeneration(config, state, basePath, targetIndex) {
904
+ const generation = {};
905
+ for (const field of CLI_GENERATION_FIELDS) {
906
+ const raw = ownValue(config, field);
907
+ if (raw === void 0) continue;
908
+ const fieldPath = [...basePath, field];
909
+ const { value, consumedPaths } = field === "profiles" && isObject(raw) ? pickProfiles(raw, fieldPath) : { value: raw, consumedPaths: [fieldPath] };
910
+ const parsed = cliGenerationConfigSchema.shape[field].safeParse(value);
911
+ consumedPaths.forEach((path) => consume(state, path));
912
+ if (parsed.success) {
913
+ generation[field] = structuredClone(value);
914
+ continue;
915
+ }
916
+ const diagnostics = parsed.error.issues.map(
917
+ (issue) => invalidValueDiagnostic(field, fieldPath, issue.path, issue.message, targetIndex)
918
+ );
919
+ (state.valueDiagnostics ??= []).push(...diagnostics);
920
+ }
921
+ return generation;
922
+ }
923
+ function pickProfiles(profiles, path) {
924
+ const picked = pickKnown(profiles, PROFILES_FIELDS, path);
925
+ const provisionOperation = ownValue(profiles, "provisionOperation");
926
+ const provisionPath = [...path, "provisionOperation"];
927
+ if (isObject(provisionOperation)) {
928
+ const provision = pickKnown(provisionOperation, PROVISION_OPERATION_FIELDS, provisionPath);
929
+ picked.value.provisionOperation = provision.value;
930
+ picked.consumedPaths.push(...provision.consumedPaths);
931
+ } else if (provisionOperation !== void 0) {
932
+ picked.value.provisionOperation = provisionOperation;
933
+ picked.consumedPaths.push(provisionPath);
934
+ }
935
+ return { value: { enabled: false, ...picked.value }, consumedPaths: picked.consumedPaths };
936
+ }
937
+ function pickKnown(value, fields, path) {
938
+ const picked = {};
939
+ const consumedPaths = [];
940
+ for (const field of fields) {
941
+ const child = ownValue(value, field);
942
+ if (child === void 0) continue;
943
+ picked[field] = child;
944
+ consumedPaths.push([...path, field]);
945
+ }
946
+ return { value: picked, consumedPaths };
947
+ }
948
+ function ownValue(value, key) {
949
+ return Object.hasOwn(value, key) ? value[key] : void 0;
950
+ }
951
+ function invalidValueDiagnostic(field, fieldPath, issuePath, message, targetIndex) {
952
+ const relative = issuePath.map((part) => typeof part === "symbol" ? String(part) : part);
953
+ const sdkConfigField = ["targets", targetIndex, "generation", field];
954
+ return {
955
+ code: "FERN_CONFIG_VALUE_INVALID",
956
+ severity: "warning",
957
+ path: [...fieldPath, ...relative],
958
+ reason: `CLI setting ${field} was not migrated because SDK Config rejects it: ${message}`,
959
+ sdkConfigPath: [...sdkConfigField, ...relative],
960
+ suggestedAction: `Correct the value, then set ${sdkConfigField.join(".")} manually.`
961
+ };
962
+ }
963
+
964
+ // src/sdk-config/v1/fern-config-mapper-cli-distribution.ts
965
+ var DISTRIBUTION_KEYS = {
966
+ githubApp: { appIdSecret: "appIdSecretName", privateKeySecret: "privateKeySecretName" },
967
+ homebrew: { tap: "tap", formula: "formula", tokenEnvironmentVariable: "tokenSecretName" },
968
+ scoop: { bucket: "bucket", tokenEnvironmentVariable: "tokenSecretName" }
969
+ };
970
+ function mapCliDistribution(config, state, basePath, targetIndex) {
971
+ if (!Object.hasOwn(config, "distribution")) return;
972
+ const raw = config.distribution;
973
+ const path = [...basePath, "distribution"];
974
+ const translated = isObject(raw) ? translateDistribution(raw, path) : { value: raw, consumedPaths: [path], legacyKeys: /* @__PURE__ */ new Map() };
975
+ const parsed = cliDistributionConfigSchema.safeParse(translated.value);
976
+ translated.consumedPaths.forEach((consumedPath) => consume(state, consumedPath));
977
+ if (parsed.success) {
978
+ state.cliDistribution = { value: parsed.data, path };
979
+ return;
980
+ }
981
+ const diagnostics = parsed.error.issues.map(
982
+ (issue) => invalidDistributionDiagnostic(issue, path, translated.legacyKeys, targetIndex)
983
+ );
984
+ const reportedPaths = /* @__PURE__ */ new Set();
985
+ (state.valueDiagnostics ??= []).push(
986
+ ...diagnostics.filter(({ path: diagnosticPath }) => {
987
+ const key = diagnosticPath.join(".");
988
+ if (reportedPaths.has(key)) return false;
989
+ reportedPaths.add(key);
990
+ return true;
991
+ })
992
+ );
993
+ }
994
+ function translateDistribution(distribution, path) {
995
+ const value = {};
996
+ const consumedPaths = [];
997
+ const legacyKeys = /* @__PURE__ */ new Map();
998
+ for (const [block, keys] of Object.entries(DISTRIBUTION_KEYS)) {
999
+ if (!Object.hasOwn(distribution, block)) continue;
1000
+ const blockValue = distribution[block];
1001
+ const blockPath = [...path, block];
1002
+ if (!isObject(blockValue)) {
1003
+ value[block] = blockValue;
1004
+ consumedPaths.push(blockPath);
1005
+ continue;
1006
+ }
1007
+ const translatedBlock = {};
1008
+ for (const [legacyKey, sdkConfigKey] of Object.entries(keys)) {
1009
+ if (!Object.hasOwn(blockValue, legacyKey)) continue;
1010
+ translatedBlock[sdkConfigKey] = blockValue[legacyKey];
1011
+ consumedPaths.push([...blockPath, legacyKey]);
1012
+ legacyKeys.set(`${block}.${sdkConfigKey}`, legacyKey);
1013
+ }
1014
+ value[block] = translatedBlock;
1015
+ }
1016
+ return { value, consumedPaths, legacyKeys };
1017
+ }
1018
+ function invalidDistributionDiagnostic(issue, path, legacyKeys, targetIndex) {
1019
+ const relative = issue.path.map((part) => typeof part === "symbol" ? String(part) : part);
1020
+ const [block, field] = relative;
1021
+ const legacyField = typeof block === "string" && typeof field === "string" ? legacyKeys.get(`${block}.${field}`) : void 0;
1022
+ const legacyRelative = typeof block === "string" && legacyField !== void 0 ? [block, legacyField] : relative;
1023
+ const sdkConfigField = ["targets", targetIndex, "output", "distribution"];
1024
+ return {
1025
+ code: "FERN_CONFIG_VALUE_INVALID",
1026
+ severity: "warning",
1027
+ path: [...path, ...legacyRelative],
1028
+ reason: `CLI distribution was not migrated because SDK Config rejects it: ${issue.message}`,
1029
+ sdkConfigPath: [...sdkConfigField, ...relative],
1030
+ suggestedAction: `Correct the value, then set ${sdkConfigField.join(".")} manually.`
1031
+ };
1032
+ }
1033
+ function applyCliDistribution(output, pending, targetIndex) {
1034
+ if (pending === void 0) return { output, diagnostics: [] };
1035
+ if (output.delivery === "github") {
1036
+ return { output: { ...output, distribution: pending.value }, diagnostics: [] };
1037
+ }
1038
+ const outputPath = ["targets", targetIndex, "output"];
1039
+ return {
1040
+ output,
1041
+ diagnostics: [
1042
+ {
1043
+ code: "FERN_CLI_DISTRIBUTION_REQUIRES_GITHUB_OUTPUT",
1044
+ severity: "warning",
1045
+ path: pending.path,
1046
+ 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`,
1047
+ sdkConfigPath: [...outputPath, "distribution"],
1048
+ suggestedAction: `Set ${outputPath.join(".")}.delivery to "github" for the CLI repository and add ${outputPath.join(".")}.distribution manually, or remove distribution.`
1049
+ }
1050
+ ]
1051
+ };
1052
+ }
666
1053
 
667
1054
  // src/sdk-config/v1/fern-config-mapper-output.ts
668
1055
  function mapOutput(generator, language, index) {
@@ -671,8 +1058,19 @@ function mapOutput(generator, language, index) {
671
1058
  const outputPath = ["group", "generators", index, "outputMode"];
672
1059
  const state = { consumedPaths: /* @__PURE__ */ new Set(), credentialDiagnostics: [] };
673
1060
  if (generator.output) {
1061
+ const downloadSnippets = mapDownloadSnippets(
1062
+ generator.outputMode,
1063
+ outputPath,
1064
+ state,
1065
+ language,
1066
+ index
1067
+ );
674
1068
  return {
675
1069
  output: sanitizeNormalizedOutput(generator.output, rawOutput, state, index),
1070
+ ...optional(
1071
+ "docs",
1072
+ downloadSnippets === void 0 ? void 0 : { snippets: { enabled: downloadSnippets } }
1073
+ ),
676
1074
  unsupportedFields: state.credentialDiagnostics ?? []
677
1075
  };
678
1076
  }
@@ -688,7 +1086,8 @@ function mapOutput(generator, language, index) {
688
1086
  generator.outputMode,
689
1087
  outputPath,
690
1088
  state,
691
- index
1089
+ index,
1090
+ language
692
1091
  );
693
1092
  }
694
1093
  if (!isObject(generator.outputMode) || typeof generator.outputMode.type !== "string") {
@@ -704,14 +1103,22 @@ function mapOutput(generator, language, index) {
704
1103
  consume(state, [...outputPath, "type"]);
705
1104
  switch (output.type) {
706
1105
  case "downloadFiles":
707
- return finishOutputMapping({ output: { delivery: "zip" } }, output, outputPath, state, index);
1106
+ return finishOutputMapping(
1107
+ { output: { delivery: "zip" } },
1108
+ output,
1109
+ outputPath,
1110
+ state,
1111
+ index,
1112
+ language
1113
+ );
708
1114
  case "github":
709
1115
  return finishOutputMapping(
710
1116
  githubOutput(output, output.publishInfo, rawOutput, language, outputPath, state, index),
711
1117
  output,
712
1118
  outputPath,
713
1119
  state,
714
- index
1120
+ index,
1121
+ language
715
1122
  );
716
1123
  case "githubV2": {
717
1124
  if (!isObject(output.githubV2))
@@ -736,7 +1143,8 @@ function mapOutput(generator, language, index) {
736
1143
  output,
737
1144
  outputPath,
738
1145
  state,
739
- index
1146
+ index,
1147
+ language
740
1148
  );
741
1149
  }
742
1150
  case "publishV2": {
@@ -756,7 +1164,8 @@ function mapOutput(generator, language, index) {
756
1164
  output,
757
1165
  outputPath,
758
1166
  state,
759
- index
1167
+ index,
1168
+ language
760
1169
  );
761
1170
  }
762
1171
  case "publish": {
@@ -776,7 +1185,8 @@ function mapOutput(generator, language, index) {
776
1185
  output,
777
1186
  outputPath,
778
1187
  state,
779
- index
1188
+ index,
1189
+ language
780
1190
  );
781
1191
  }
782
1192
  default:
@@ -850,11 +1260,10 @@ function githubOutput(value, publishInfo, rawOutput, language, sourcePath, state
850
1260
  ...optionalObject("package", { ...publication?.package, ...licensePackage })
851
1261
  };
852
1262
  }
853
- var basicLicenseTypes = { mit: "MIT", apache: "APACHE" };
854
1263
  function mapGithubLicense(value, sourcePath, state) {
855
1264
  if (!isObject(value) || stringValue(value.type) !== "basic") return {};
856
1265
  const id = stringValue(value.id);
857
- const type = id ? basicLicenseTypes[id.toLowerCase()] : void 0;
1266
+ const type = id ? canonicalLicenseType(id) : void 0;
858
1267
  if (!type) return {};
859
1268
  consume(state, [...sourcePath, "type"]);
860
1269
  consume(state, [...sourcePath, "id"]);
@@ -1283,7 +1692,8 @@ function mapAuthors(value, sourcePath, state) {
1283
1692
  });
1284
1693
  return authors;
1285
1694
  }
1286
- function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1695
+ function finishOutputMapping(mapping, outputMode, sourcePath, state, index, language) {
1696
+ const downloadSnippets = mapDownloadSnippets(outputMode, sourcePath, state, language, index);
1287
1697
  for (const path of collectLeafPaths(outputMode, sourcePath)) {
1288
1698
  if (path[path.length - 1] === "_visit") consume(state, path);
1289
1699
  }
@@ -1291,6 +1701,10 @@ function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1291
1701
  const hasCredentials = unsupported.some((diagnostic) => isCredentialPath(diagnostic.path));
1292
1702
  return {
1293
1703
  ...mapping,
1704
+ ...optional(
1705
+ "docs",
1706
+ downloadSnippets === void 0 ? void 0 : { snippets: { enabled: downloadSnippets } }
1707
+ ),
1294
1708
  unsupportedFields: [
1295
1709
  ...state.credentialDiagnostics ?? [],
1296
1710
  ...hasCredentials ? [
@@ -1310,6 +1724,45 @@ function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1310
1724
  ]
1311
1725
  };
1312
1726
  }
1727
+ function mapDownloadSnippets(value, sourcePath, state, language, index) {
1728
+ if (!isObject(value)) return void 0;
1729
+ const candidates = [];
1730
+ switch (value.type) {
1731
+ case "downloadFiles":
1732
+ case "github":
1733
+ candidates.push({ value, path: sourcePath });
1734
+ break;
1735
+ case "githubV2":
1736
+ if (isObject(value.githubV2)) {
1737
+ candidates.push({ value: value.githubV2, path: [...sourcePath, "githubV2"] });
1738
+ }
1739
+ break;
1740
+ case "publishV2":
1741
+ if (isObject(value.publishV2)) {
1742
+ candidates.push({ value: value.publishV2, path: [...sourcePath, "publishV2"] });
1743
+ }
1744
+ break;
1745
+ case "publish":
1746
+ if (isObject(value.registryOverrides)) {
1747
+ const registry = defaultRegistry(language, [...sourcePath, "registryOverrides"], index);
1748
+ const override = value.registryOverrides[registry];
1749
+ if (isObject(override)) {
1750
+ candidates.push({
1751
+ value: override,
1752
+ path: [...sourcePath, "registryOverrides", registry]
1753
+ });
1754
+ }
1755
+ }
1756
+ break;
1757
+ }
1758
+ let enabled;
1759
+ for (const candidate of candidates) {
1760
+ if (typeof candidate.value.downloadSnippets !== "boolean") continue;
1761
+ consume(state, [...candidate.path, "downloadSnippets"]);
1762
+ enabled = enabled === true || candidate.value.downloadSnippets;
1763
+ }
1764
+ return enabled;
1765
+ }
1313
1766
  function isCredentialPath(path) {
1314
1767
  const fields = path.filter((part) => typeof part === "string");
1315
1768
  const field = fields[fields.length - 1];
@@ -1377,6 +1830,114 @@ function outputDiagnostic(path, index) {
1377
1830
  suggestedAction: resolvedGuidance?.suggestedAction ?? "Review this output setting and preserve it outside SDK Config when no equivalent exists."
1378
1831
  };
1379
1832
  }
1833
+
1834
+ // src/sdk-config/v1/package.ts
1835
+ var sdkConfigV1DependencySchema = dependencySchema;
1836
+ var sdkConfigV1PackageConfigSchema = packageConfigSchema;
1837
+
1838
+ // src/sdk-config/v1/fern-config-mapper-package.ts
1839
+ var emailSchema = z.email();
1840
+ function mapCliPackageIdentity(identity, state, targetIndex) {
1841
+ mapIdentityField(identity, "homepage", stringValue, state);
1842
+ mapIdentityField(identity, "keywords", (value) => stringArrayValue(value)?.slice(), state);
1843
+ mapCargoAuthors(identity, state, targetIndex);
1844
+ mapIdentityField(identity, "license", licenseValue, state);
1845
+ }
1846
+ function mapIdentityField(identity, field, read, state) {
1847
+ const located = locate(identity.value, [field], identity.path);
1848
+ const value = located && read(located.value);
1849
+ if (located && value !== void 0) addPackageFallback(state, field, value, located.path);
1850
+ }
1851
+ function mapLicenseFallback(config, aliases, state, basePath) {
1852
+ const located = locate(config, aliases, basePath);
1853
+ const license = located && licenseValue(located.value);
1854
+ if (located && license) addPackageFallback(state, "license", license, located.path);
1855
+ }
1856
+ function resolveTargetPackage(targetPackage, fallbacks, generator, delivery, index) {
1857
+ const diagnostics = [];
1858
+ for (const fallback of fallbacks) {
1859
+ applyFallback(targetPackage, fallback, index, diagnostics);
1860
+ }
1861
+ if (delivery !== "github") {
1862
+ applyMetadataLicense(targetPackage, generator.raw, index, diagnostics);
1863
+ }
1864
+ return diagnostics;
1865
+ }
1866
+ function applyFallback(targetPackage, { field, value, path }, index, diagnostics) {
1867
+ const existing = targetPackage[field];
1868
+ if (existing === void 0) {
1869
+ targetPackage[field] = value;
1870
+ } else if (stableJson(existing) !== stableJson(value)) {
1871
+ diagnostics.push({
1872
+ code: "FERN_PACKAGE_VALUE_CONFLICT",
1873
+ severity: "warning",
1874
+ path,
1875
+ reason: `Fern value conflicts with the package.${field} already migrated for this target, which is kept`,
1876
+ sdkConfigPath: ["targets", index, "package", field],
1877
+ suggestedAction: `Choose the intended value and set targets.${index}.package.${field} manually.`
1878
+ });
1879
+ }
1880
+ }
1881
+ function applyMetadataLicense(targetPackage, raw, index, diagnostics) {
1882
+ const metadata = isObject(raw) && isObject(raw.metadata) ? raw.metadata : void 0;
1883
+ if (metadata?.license === void 0 || metadata.license === null) return;
1884
+ const path = ["group", "generators", index, "metadata", "license"];
1885
+ const license = licenseValue(metadata.license);
1886
+ if (license) {
1887
+ applyFallback(targetPackage, { field: "license", value: license, path }, index, diagnostics);
1888
+ return;
1889
+ }
1890
+ diagnostics.push({
1891
+ code: "FERN_CONFIG_FIELD_UNSUPPORTED",
1892
+ severity: "warning",
1893
+ path,
1894
+ reason: isObject(metadata.license) ? "A custom license file cannot be migrated automatically" : "metadata.license is not a license identifier",
1895
+ sdkConfigPath: ["targets", index, "package", "license"],
1896
+ suggestedAction: `Set targets.${index}.package.license manually.`
1897
+ });
1898
+ }
1899
+ function mapCargoAuthors(identity, state, targetIndex) {
1900
+ const located = locate(identity.value, ["authors"], identity.path);
1901
+ const entries = located && stringArrayValue(located.value);
1902
+ if (!located || !entries) return;
1903
+ consume(state, located.path);
1904
+ const authors = entries.map(parseCargoAuthor);
1905
+ const parsed = sdkConfigV1PackageConfigSchema.shape.authors.safeParse(authors);
1906
+ const invalid = parsed.success ? [] : [...new Set(parsed.error.issues.map((issue) => issue.path[0]))].filter(
1907
+ (index) => typeof index === "number"
1908
+ );
1909
+ if (invalid.length === 0) {
1910
+ addPackageFallback(state, "authors", authors, located.path);
1911
+ return;
1912
+ }
1913
+ const authorsPath = ["targets", targetIndex, "package", "authors"];
1914
+ (state.valueDiagnostics ??= []).push(
1915
+ ...invalid.map((entry) => ({
1916
+ code: "FERN_CONFIG_VALUE_INVALID",
1917
+ severity: "warning",
1918
+ path: [...located.path, entry],
1919
+ reason: 'CLI packageIdentity.authors was not migrated because this entry is not "Name" or "Name <email>" with a valid email',
1920
+ sdkConfigPath: authorsPath,
1921
+ suggestedAction: `Correct the entry, then set ${authorsPath.join(".")} manually.`
1922
+ }))
1923
+ );
1924
+ }
1925
+ function parseCargoAuthor(entry) {
1926
+ const trimmed = entry.trim();
1927
+ const match = /^(.*?)\s*<([^<>]*)>$/.exec(trimmed);
1928
+ if (!match) return { name: trimmed };
1929
+ const [, name = "", email = ""] = match;
1930
+ if (name !== "" && !emailSchema.safeParse(email).success) return { name: trimmed };
1931
+ return { name, email };
1932
+ }
1933
+ function licenseValue(value) {
1934
+ const license = stringValue(value)?.trim();
1935
+ return license ? { type: canonicalLicenseType(license) ?? license } : void 0;
1936
+ }
1937
+ function addPackageFallback(state, field, value, path) {
1938
+ consume(state, path);
1939
+ (state.packageFallbacks ??= []).push({ field, value, path });
1940
+ }
1380
1941
  var OMIT = /* @__PURE__ */ Symbol("omit");
1381
1942
  function inputJsonSchema(schema) {
1382
1943
  return z.toJSONSchema(schema, {
@@ -1634,7 +2195,16 @@ var sdkConfigV1PublishConfigSchema = z.discriminatedUnion("registry", [
1634
2195
  z.strictObject({
1635
2196
  registry: z.literal("npm").describe("Publishes the package to an npm-compatible registry."),
1636
2197
  token: nonEmptyStringSchema.optional().describe("The npm registry token, or an environment expression that resolves to it."),
2198
+ trustedPublishing: z.boolean().optional().describe("Whether npm publication uses trusted publishing (OIDC) instead of a token."),
1637
2199
  ...commonPublishShape
2200
+ }).superRefine((publish, context) => {
2201
+ if (publish.trustedPublishing === true && publish.token !== void 0) {
2202
+ context.addIssue({
2203
+ code: "custom",
2204
+ message: "token must be omitted when trustedPublishing is true",
2205
+ path: ["token"]
2206
+ });
2207
+ }
1638
2208
  }),
1639
2209
  z.strictObject({
1640
2210
  registry: z.literal("pypi").describe("Publishes the package to a PyPI-compatible registry."),
@@ -1712,10 +2282,29 @@ var sdkConfigV1OutputConfigSchema = z.discriminatedUnion(
1712
2282
  [filesOutputSchema, zipOutputSchema, githubDeliverySchema],
1713
2283
  { error: 'output.delivery must be one of "files", "zip", or "github"' }
1714
2284
  );
1715
-
1716
- // src/sdk-config/v1/package.ts
1717
- var sdkConfigV1DependencySchema = dependencySchema;
1718
- var sdkConfigV1PackageConfigSchema = packageConfigSchema;
2285
+ var cliDistributionShape = {
2286
+ distribution: cliDistributionConfigSchema.optional().describe(
2287
+ "CLI release channels published by the generated release workflow; credentials are GitHub Actions secret names."
2288
+ )
2289
+ };
2290
+ function rejectDistributionWithoutGithub(output, context) {
2291
+ if (output.distribution !== void 0) {
2292
+ context.addIssue({
2293
+ code: "custom",
2294
+ message: CLI_DISTRIBUTION_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2295
+ path: ["distribution"]
2296
+ });
2297
+ }
2298
+ }
2299
+ var sdkConfigV1CliOutputConfigSchema = z.discriminatedUnion(
2300
+ "delivery",
2301
+ [
2302
+ filesOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2303
+ zipOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2304
+ githubDeliverySchema.extend(cliDistributionShape)
2305
+ ],
2306
+ { error: 'output.delivery must be one of "files", "zip", or "github"' }
2307
+ );
1719
2308
  var sdkConfigV1ReplayConfigSchema = z.strictObject({
1720
2309
  enabled: z.boolean().describe("Whether regeneration reapplies customer-authored repository changes.")
1721
2310
  });
@@ -1792,10 +2381,6 @@ var sdkConfigV1SourceConfigSchema = z.strictObject({
1792
2381
  seenIds.add(id);
1793
2382
  });
1794
2383
  });
1795
- var cliGenerationConfigSchema = z.strictObject({
1796
- paginationParameters: z.array(nonEmptyStringSchema).optional().describe("Request parameter names treated as pagination controls by the CLI."),
1797
- skills: z.boolean().optional().describe("Whether the generated CLI includes skills that teach AI agents to invoke commands.")
1798
- });
1799
2384
  var csharpGenerationConfigSchema = z.strictObject({
1800
2385
  useOptionalWrapper: z.boolean().optional().describe("Whether optional values use an explicit Optional wrapper."),
1801
2386
  simplifyObjectDictionaries: z.boolean().optional().describe("Whether object schemas with arbitrary values use simplified dictionary types."),
@@ -2048,7 +2633,10 @@ var sdkConfigV1TargetSchema = z.discriminatedUnion("language", [
2048
2633
  z.strictObject({
2049
2634
  language: z.literal("cli").describe("Generates a command-line interface."),
2050
2635
  generation: sdkConfigV1GenerationConfigOverrideSchema.extend(cliGenerationConfigSchema.shape).optional().describe("Common and CLI-specific generation settings for this target."),
2051
- ...targetOverrideShape
2636
+ ...targetOverrideShape,
2637
+ output: sdkConfigV1CliOutputConfigSchema.optional().describe(
2638
+ "Output configuration, including optional CLI distribution channels, that replaces the root output for this target."
2639
+ )
2052
2640
  }),
2053
2641
  z.strictObject({
2054
2642
  language: z.literal("mcp").describe("Generates an MCP server."),
@@ -2065,7 +2653,7 @@ var sdkConfigV1TargetSchema = z.discriminatedUnion("language", [
2065
2653
  // src/sdk-config/v1/sdk-config-v1.ts
2066
2654
  var SDK_CONFIG_V1_SCHEMA_VERSION = "sdk-config/v1";
2067
2655
  var publishRegistryLanguages = {
2068
- npm: ["typescript", "mcp"],
2656
+ npm: ["typescript", "mcp", "cli"],
2069
2657
  pypi: ["python"],
2070
2658
  maven: ["java", "kotlin"],
2071
2659
  nuget: ["csharp"],
@@ -2142,6 +2730,13 @@ function validateTargetPublishing(target, targetIndex, globalPackage, globalOutp
2142
2730
  });
2143
2731
  return;
2144
2732
  }
2733
+ if (target.language === "cli" && output.delivery !== "github") {
2734
+ context.addIssue({
2735
+ code: "custom",
2736
+ message: CLI_PUBLISH_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2737
+ path: target.output ? ["targets", targetIndex, "output", "delivery"] : ["output", "delivery"]
2738
+ });
2739
+ }
2145
2740
  validatePublishingIdentity(
2146
2741
  { ...globalPackage, ...target.package },
2147
2742
  registry,
@@ -2233,11 +2828,12 @@ function mapFernConfigToSdkConfigV1(input) {
2233
2828
  generator,
2234
2829
  language,
2235
2830
  invocation,
2236
- ...outputMapping
2831
+ ...outputMapping,
2832
+ docs: { ...invocation.docs, ...outputMapping.docs }
2237
2833
  };
2238
2834
  });
2239
2835
  const clients = partitionSharedBlock(mapped.map(({ invocation }) => invocation.client));
2240
- const docs = partitionSharedBlock(mapped.map(({ invocation }) => invocation.docs));
2836
+ const docs = partitionSharedBlock(mapped.map(({ docs: docs2 }) => docs2));
2241
2837
  const generations = partitionSharedBlock(mapped.map(({ invocation }) => invocation.generation));
2242
2838
  const api = { ...input.api ?? {} };
2243
2839
  delete api.audiences;
@@ -2253,16 +2849,28 @@ function mapFernConfigToSdkConfigV1(input) {
2253
2849
  package: outputPackage,
2254
2850
  generation: outputGeneration
2255
2851
  }, index) => {
2852
+ const distribution = applyCliDistribution(output, invocation.cliDistribution, index);
2853
+ invocation.unsupportedFields.push(...distribution.diagnostics);
2256
2854
  const target = {
2257
2855
  language,
2258
- output,
2856
+ output: distribution.output,
2259
2857
  ...optional("sdkName", generator.sdkName),
2260
2858
  ...optional("sdkVersion", generator.sdkVersion),
2261
2859
  ...optional("client", clients.targetOverrides[index]),
2262
2860
  ...optional("docs", docs.targetOverrides[index])
2263
2861
  };
2264
- if (Object.keys(invocation.package).length > 0 || outputPackage || generator.package) {
2265
- target.package = { ...invocation.package, ...outputPackage, ...generator.package };
2862
+ const targetPackage = { ...invocation.package, ...outputPackage, ...generator.package };
2863
+ invocation.unsupportedFields.push(
2864
+ ...resolveTargetPackage(
2865
+ targetPackage,
2866
+ invocation.packageFallbacks,
2867
+ generator,
2868
+ output.delivery,
2869
+ index
2870
+ )
2871
+ );
2872
+ if (Object.keys(targetPackage).length > 0 || outputPackage || generator.package) {
2873
+ target.package = targetPackage;
2266
2874
  }
2267
2875
  const targetGeneration = {
2268
2876
  ...generations.targetOverrides[index],
@@ -2444,10 +3052,14 @@ function mapInvocation(generator, language, activeLanguages, index) {
2444
3052
  ...optional("smartCasingDigitWordBoundary", smartCasingDigitWordBoundary)
2445
3053
  };
2446
3054
  }
2447
- const targetGeneration = mapLanguageConfig(language, config, state, packageConfig, [
2448
- ...prefix,
2449
- "config"
2450
- ]);
3055
+ const targetGeneration = mapLanguageConfig(
3056
+ language,
3057
+ config,
3058
+ state,
3059
+ packageConfig,
3060
+ [...prefix, "config"],
3061
+ index
3062
+ );
2451
3063
  mapPublishMetadata(generator.publishMetadata, packageConfig);
2452
3064
  if (generator.keywords?.length) {
2453
3065
  generation.reservedKeywords = [...generator.keywords];
@@ -2464,12 +3076,22 @@ function mapInvocation(generator, language, activeLanguages, index) {
2464
3076
  }
2465
3077
  const docs = mapReadme(generator.readme, language, activeLanguages, state, [...prefix, "readme"]);
2466
3078
  const unsupportedFields = [
3079
+ ...state.valueDiagnostics ?? [],
2467
3080
  ...collectUnsupported(config, [...prefix, "config"], state),
2468
3081
  ...settings ? collectUnsupported(settings, [...prefix, "settings"], state) : [],
2469
3082
  ...isObject(generator.readme) ? collectUnsupported(generator.readme, [...prefix, "readme"], state) : [],
2470
3083
  ...unsupportedResolvedFields(generator, index, apiWideIdempotency !== void 0)
2471
3084
  ];
2472
- return { client, docs, generation, package: packageConfig, targetGeneration, unsupportedFields };
3085
+ return {
3086
+ client,
3087
+ docs,
3088
+ generation,
3089
+ package: packageConfig,
3090
+ packageFallbacks: state.packageFallbacks ?? [],
3091
+ ...optional("cliDistribution", state.cliDistribution),
3092
+ targetGeneration,
3093
+ unsupportedFields
3094
+ };
2473
3095
  }
2474
3096
  function unsupportedResolvedFields(generator, index, idempotencyMapped) {
2475
3097
  const values = [
@@ -2659,6 +3281,7 @@ function mapCommonConfig(language, config, state, client, generation, packageCon
2659
3281
  const packagePath = takeString(config, ["packagePath"], state, basePath);
2660
3282
  if (packagePath !== void 0) generation.layout = { packagePath };
2661
3283
  mapDependencies(config, state, packageConfig, basePath);
3284
+ mapPeerDependenciesMeta(config, state, packageConfig, basePath);
2662
3285
  }
2663
3286
  function mapTypescriptStreams(config, state, basePath) {
2664
3287
  const responseType = takeEnum(config, ["streamType"], ["wrapper", "web"], state, basePath);
@@ -2672,7 +3295,7 @@ function mapTypescriptStreams(config, state, basePath) {
2672
3295
  if (responseType === void 0 && fileResponseType === void 0) return void 0;
2673
3296
  return { enabled: true, ...compact({ responseType, fileResponseType }) };
2674
3297
  }
2675
- function mapLanguageConfig(language, config, state, packageConfig, basePath) {
3298
+ function mapLanguageConfig(language, config, state, packageConfig, basePath, targetIndex) {
2676
3299
  switch (language) {
2677
3300
  case "typescript":
2678
3301
  return mapTypescript(config, state, packageConfig, basePath);
@@ -2699,7 +3322,7 @@ function mapLanguageConfig(language, config, state, packageConfig, basePath) {
2699
3322
  case "swift":
2700
3323
  return mapSwift(config, state, basePath);
2701
3324
  case "cli":
2702
- return mapCli(config, state, packageConfig, basePath);
3325
+ return mapCli(config, state, packageConfig, basePath, targetIndex);
2703
3326
  case "terraform":
2704
3327
  return mapTerraform(config, state, packageConfig, basePath);
2705
3328
  }
@@ -2716,6 +3339,7 @@ function mapTypescript(config, state, packageConfig, basePath) {
2716
3339
  const packageManagerAtIndex = packageJsonPackageManager ? packageJsonPackageManager.indexOf("@", packageJsonPackageManager.startsWith("@") ? 1 : 0) : -1;
2717
3340
  const packageManagerVersionPart = packageManagerAtIndex >= 0 ? packageJsonPackageManager?.slice(packageManagerAtIndex + 1).split("+")[0] : void 0;
2718
3341
  const packageManagerVersion = packageManagerVersionPart || void 0;
3342
+ if (packageJsonManifest) liftPackageJsonDependencies(packageJsonManifest, state, packageConfig);
2719
3343
  const serdeLayer = takeBoolean(config, ["serdeLayer"], state, basePath);
2720
3344
  const noSerdeLayer = takeBoolean(config, ["noSerdeLayer"], state, basePath);
2721
3345
  const fetchSupport = takeEnum(config, ["fetchSupport"], ["native"], state, basePath);
@@ -2772,7 +3396,8 @@ function mapPython(config, state, packageConfig, basePath) {
2772
3396
  });
2773
3397
  }
2774
3398
  function mapJvm(language, config, state, packageConfig, basePath) {
2775
- const namespace = takeString(config, ["packageName", "packagePrefix"], state, basePath);
3399
+ const namespaceAliases = language === "java" ? ["packagePrefix"] : ["packageName", "packagePrefix"];
3400
+ const namespace = takeString(config, namespaceAliases, state, basePath);
2776
3401
  const groupId = takeString(config, ["group", "groupId"], state, basePath);
2777
3402
  const artifactId = takeString(config, ["artifact", "artifactId"], state, basePath);
2778
3403
  if (namespace !== void 0) packageConfig.namespace = namespace;
@@ -2884,6 +3509,7 @@ function mapRust(config, state, packageConfig, basePath) {
2884
3509
  const description = takeString(config, ["packageDescription"], state, basePath);
2885
3510
  const documentationUrl = takeString(config, ["packageDocumentation"], state, basePath);
2886
3511
  Object.assign(packageConfig, compact({ packageName, repository, description, documentationUrl }));
3512
+ mapLicenseFallback(config, ["packageLicense"], state, basePath);
2887
3513
  return compact({
2888
3514
  dateTimeType: takeEnum(config, ["dateTimeType"], ["offset", "utc"], state, basePath),
2889
3515
  capitalizeInitialisms: takeBoolean(config, ["capitalizeInitialisms"], state, basePath),
@@ -2897,7 +3523,7 @@ function mapSwift(config, state, basePath) {
2897
3523
  nullableAsOptional: takeBoolean(config, ["nullableAsOptional"], state, basePath)
2898
3524
  });
2899
3525
  }
2900
- function mapCli(config, state, packageConfig, basePath) {
3526
+ function mapCli(config, state, packageConfig, basePath, targetIndex) {
2901
3527
  const identity = takeObject(config, ["packageIdentity"], state, basePath);
2902
3528
  if (identity) {
2903
3529
  Object.assign(
@@ -2908,10 +3534,13 @@ function mapCli(config, state, packageConfig, basePath) {
2908
3534
  description: takeString(identity.value, ["description"], state, identity.path)
2909
3535
  })
2910
3536
  );
3537
+ mapCliPackageIdentity(identity, state, targetIndex);
2911
3538
  }
3539
+ mapCliDistribution(config, state, basePath, targetIndex);
2912
3540
  return compact({
2913
3541
  paginationParameters: takeStringArray(config, ["paginationParameters"], state, basePath),
2914
- skills: takeBoolean(config, ["skills"], state, basePath)
3542
+ skills: takeBoolean(config, ["skills"], state, basePath),
3543
+ ...mapCliGeneration(config, state, basePath, targetIndex)
2915
3544
  });
2916
3545
  }
2917
3546
  function mapTerraform(config, state, packageConfig, basePath) {
@@ -2995,6 +3624,48 @@ function mapDependencies(config, state, packageConfig, basePath) {
2995
3624
  if (dependencies.length) packageConfig[field] = dependencies;
2996
3625
  }
2997
3626
  }
3627
+ function liftPackageJsonDependencies(manifest, state, packageConfig) {
3628
+ for (const [field, target] of [
3629
+ ["dependencies", "extraDependencies"],
3630
+ ["devDependencies", "extraDevDependencies"],
3631
+ ["peerDependencies", "extraPeerDependencies"]
3632
+ ]) {
3633
+ const located = takeObject(manifest.value, [field], state, manifest.path);
3634
+ if (!located) continue;
3635
+ const lifted = Object.entries(located.value).flatMap(
3636
+ ([name, dependency]) => mapDependency(name, dependency, state, [...located.path, name])
3637
+ );
3638
+ if (lifted.length) packageConfig[target] = overrideByName(packageConfig[target] ?? [], lifted);
3639
+ }
3640
+ const meta = takeObject(manifest.value, ["peerDependenciesMeta"], state, manifest.path);
3641
+ if (!meta) return;
3642
+ const entries = peerDependenciesMetaEntries(meta, state);
3643
+ if (entries.length) {
3644
+ packageConfig.extraPeerDependenciesMeta = {
3645
+ ...packageConfig.extraPeerDependenciesMeta,
3646
+ ...Object.fromEntries(entries)
3647
+ };
3648
+ }
3649
+ }
3650
+ function overrideByName(existing, overrides) {
3651
+ const byName = new Map(existing.map((dependency) => [dependency.name, dependency]));
3652
+ overrides.forEach((dependency) => byName.set(dependency.name, dependency));
3653
+ return [...byName.values()];
3654
+ }
3655
+ function mapPeerDependenciesMeta(config, state, packageConfig, basePath) {
3656
+ const located = takeObject(config, ["extraPeerDependenciesMeta"], state, basePath);
3657
+ if (!located) return;
3658
+ const entries = peerDependenciesMetaEntries(located, state);
3659
+ if (entries.length) packageConfig.extraPeerDependenciesMeta = Object.fromEntries(entries);
3660
+ }
3661
+ function peerDependenciesMetaEntries(located, state) {
3662
+ return Object.entries(located.value).flatMap(([name, value]) => {
3663
+ const parsed = jsonObjectSchema.safeParse(value);
3664
+ if (!parsed.success) return [];
3665
+ consume(state, [...located.path, name]);
3666
+ return [[name, parsed.data]];
3667
+ });
3668
+ }
2998
3669
  function mapDependency(name, value, state, path) {
2999
3670
  if (typeof value === "string" && value) {
3000
3671
  consume(state, path);
@@ -3002,13 +3673,7 @@ function mapDependency(name, value, state, path) {
3002
3673
  }
3003
3674
  if (!isObject(value)) return [];
3004
3675
  const version = takeString(value, ["version"], state, path);
3005
- const gitUrl = takeString(value, ["git"], state, path);
3006
- const localPath = takeString(value, ["path"], state, path);
3007
- const source = gitUrl ? {
3008
- type: "git",
3009
- url: gitUrl,
3010
- ...optional("ref", takeString(value, ["ref"], state, path))
3011
- } : localPath ? { type: "path", path: localPath } : void 0;
3676
+ const source = takeDependencySource(value, state, path);
3012
3677
  if (!version && !source) return [];
3013
3678
  return [
3014
3679
  {
@@ -3024,6 +3689,17 @@ function mapDependency(name, value, state, path) {
3024
3689
  }
3025
3690
  ];
3026
3691
  }
3692
+ function takeDependencySource(value, state, path) {
3693
+ const gitUrl = takeString(value, ["git"], state, path);
3694
+ if (gitUrl) {
3695
+ const ref = takeString(value, ["ref", "rev", "branch"], state, path);
3696
+ return { type: "git", url: gitUrl, ...optional("ref", ref) };
3697
+ }
3698
+ const localPath = takeString(value, ["path"], state, path);
3699
+ if (localPath) return { type: "path", path: localPath };
3700
+ const registry = takeString(value, ["registry"], state, path);
3701
+ return registry ? { type: "registry", registry } : void 0;
3702
+ }
3027
3703
  function takeCustomSections(value, language, activeLanguages, state, basePath) {
3028
3704
  const located = locate(value, ["customSections"], basePath);
3029
3705
  if (!located || !Array.isArray(located.value)) return void 0;
@@ -3182,6 +3858,6 @@ function takeToolsets(value, aliases, state, basePath) {
3182
3858
  return Object.fromEntries(entries.filter((entry) => entry !== void 0));
3183
3859
  }
3184
3860
 
3185
- export { FernConfigMappingError, SDK_CONFIG_V1_SCHEMA_VERSION, mapFernConfigToSdkConfigV1, parseSdkConfigV1, parseSdkConfigV1ForConsumption, sdkConfigV1ApiConfigSchema, sdkConfigV1AuthConfigSchema, sdkConfigV1AuthSchemeSchema, cliGenerationConfigSchema as sdkConfigV1CliGenerationConfigSchema, sdkConfigV1ClientConfigOverrideSchema, sdkConfigV1ClientConfigSchema, composerPackageNameSchema as sdkConfigV1ComposerPackageNameSchema, csharpGenerationConfigSchema as sdkConfigV1CsharpGenerationConfigSchema, sdkConfigV1DependencySchema, sdkConfigV1DocsConfigSchema, exactSemverSchema as sdkConfigV1ExactSemverSchema, sdkConfigV1GenerationConfigOverrideSchema, sdkConfigV1GenerationConfigSchema, goGenerationConfigSchema as sdkConfigV1GoGenerationConfigSchema, goModulePathSchema as sdkConfigV1GoModulePathSchema, javaGenerationConfigSchema as sdkConfigV1JavaGenerationConfigSchema, kotlinGenerationConfigSchema as sdkConfigV1KotlinGenerationConfigSchema, mcpGenerationConfigSchema as sdkConfigV1McpGenerationConfigSchema, nonEmptyStringSchema as sdkConfigV1NonEmptyStringSchema, sdkConfigV1OutputConfigSchema, sdkConfigV1PackageConfigSchema, phpGenerationConfigSchema as sdkConfigV1PhpGenerationConfigSchema, sdkConfigV1PublishConfigSchema, sdkConfigV1PublishRegistrySchema, pythonGenerationConfigSchema as sdkConfigV1PythonGenerationConfigSchema, sdkConfigV1ReadmeCustomSectionSchema, sdkConfigV1ReadmeEndpointSchema, relativePathSchema as sdkConfigV1RelativePathSchema, sdkConfigV1ReplayConfigSchema, rubyGenerationConfigSchema as sdkConfigV1RubyGenerationConfigSchema, rustGenerationConfigSchema as sdkConfigV1RustGenerationConfigSchema, sdkConfigV1Schema, sdkConfigV1SourceConfigSchema, sdkConfigV1SourceSpecSchema, swiftGenerationConfigSchema as sdkConfigV1SwiftGenerationConfigSchema, sdkConfigV1TargetSchema, terraformGenerationConfigSchema as sdkConfigV1TerraformGenerationConfigSchema, typescriptGenerationConfigSchema as sdkConfigV1TypescriptGenerationConfigSchema, sdkConfigV1WebhookSignatureSchema, splitSdkConfigV1TargetGeneration, validateSdkConfigV1 };
3861
+ export { FernConfigMappingError, CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE as SDK_CONFIG_V1_CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE, SDK_CONFIG_V1_SCHEMA_VERSION, getSdkConfigV1Diagnostics, mapFernConfigToSdkConfigV1, parseSdkConfigV1, parseSdkConfigV1ForConsumption, sdkConfigV1ApiConfigSchema, sdkConfigV1AuthConfigSchema, sdkConfigV1AuthSchemeSchema, cliDistributionConfigSchema as sdkConfigV1CliDistributionConfigSchema, cliDistributionGithubAppSchema as sdkConfigV1CliDistributionGithubAppSchema, cliDistributionHomebrewSchema as sdkConfigV1CliDistributionHomebrewSchema, cliDistributionScoopSchema as sdkConfigV1CliDistributionScoopSchema, cliGenerationConfigSchema as sdkConfigV1CliGenerationConfigSchema, sdkConfigV1CliOutputConfigSchema, sdkConfigV1ClientConfigOverrideSchema, sdkConfigV1ClientConfigSchema, composerPackageNameSchema as sdkConfigV1ComposerPackageNameSchema, csharpGenerationConfigSchema as sdkConfigV1CsharpGenerationConfigSchema, sdkConfigV1DependencySchema, sdkConfigV1DocsConfigSchema, exactSemverSchema as sdkConfigV1ExactSemverSchema, sdkConfigV1GenerationConfigOverrideSchema, sdkConfigV1GenerationConfigSchema, githubActionsSecretNameSchema as sdkConfigV1GithubActionsSecretNameSchema, goGenerationConfigSchema as sdkConfigV1GoGenerationConfigSchema, goModulePathSchema as sdkConfigV1GoModulePathSchema, javaGenerationConfigSchema as sdkConfigV1JavaGenerationConfigSchema, kotlinGenerationConfigSchema as sdkConfigV1KotlinGenerationConfigSchema, mcpGenerationConfigSchema as sdkConfigV1McpGenerationConfigSchema, nonEmptyStringSchema as sdkConfigV1NonEmptyStringSchema, sdkConfigV1OutputConfigSchema, sdkConfigV1PackageConfigSchema, phpGenerationConfigSchema as sdkConfigV1PhpGenerationConfigSchema, sdkConfigV1PublishConfigSchema, sdkConfigV1PublishRegistrySchema, pythonGenerationConfigSchema as sdkConfigV1PythonGenerationConfigSchema, sdkConfigV1ReadmeCustomSectionSchema, sdkConfigV1ReadmeEndpointSchema, relativePathSchema as sdkConfigV1RelativePathSchema, sdkConfigV1ReplayConfigSchema, rubyGenerationConfigSchema as sdkConfigV1RubyGenerationConfigSchema, rustGenerationConfigSchema as sdkConfigV1RustGenerationConfigSchema, sdkConfigV1Schema, sdkConfigV1SourceConfigSchema, sdkConfigV1SourceSpecSchema, swiftGenerationConfigSchema as sdkConfigV1SwiftGenerationConfigSchema, sdkConfigV1TargetSchema, terraformGenerationConfigSchema as sdkConfigV1TerraformGenerationConfigSchema, typescriptGenerationConfigSchema as sdkConfigV1TypescriptGenerationConfigSchema, sdkConfigV1WebhookSignatureSchema, splitSdkConfigV1TargetGeneration, validateSdkConfigV1 };
3186
3862
  //# sourceMappingURL=index.js.map
3187
3863
  //# sourceMappingURL=index.js.map