@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
@@ -33,7 +33,7 @@ var jsonValueSchema = zod.z.lazy(
33
33
  zod.z.record(zod.z.string(), jsonValueSchema)
34
34
  ])
35
35
  );
36
- zod.z.record(zod.z.string(), jsonValueSchema);
36
+ var jsonObjectSchema = zod.z.record(zod.z.string(), jsonValueSchema);
37
37
  var hashAlgorithmSchema = zod.z.enum(["sha1", "sha256", "sha384", "sha512"]);
38
38
  var encodingSchema = zod.z.enum(["base64", "hex"]);
39
39
  var payloadComponentSchema = zod.z.enum(["body", "timestamp", "notification-url", "message-id"]);
@@ -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
+ )
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)
457
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) {
@@ -677,8 +1064,19 @@ function mapOutput(generator, language, index) {
677
1064
  const outputPath = ["group", "generators", index, "outputMode"];
678
1065
  const state = { consumedPaths: /* @__PURE__ */ new Set(), credentialDiagnostics: [] };
679
1066
  if (generator.output) {
1067
+ const downloadSnippets = mapDownloadSnippets(
1068
+ generator.outputMode,
1069
+ outputPath,
1070
+ state,
1071
+ language,
1072
+ index
1073
+ );
680
1074
  return {
681
1075
  output: sanitizeNormalizedOutput(generator.output, rawOutput, state, index),
1076
+ ...optional(
1077
+ "docs",
1078
+ downloadSnippets === void 0 ? void 0 : { snippets: { enabled: downloadSnippets } }
1079
+ ),
682
1080
  unsupportedFields: state.credentialDiagnostics ?? []
683
1081
  };
684
1082
  }
@@ -694,7 +1092,8 @@ function mapOutput(generator, language, index) {
694
1092
  generator.outputMode,
695
1093
  outputPath,
696
1094
  state,
697
- index
1095
+ index,
1096
+ language
698
1097
  );
699
1098
  }
700
1099
  if (!isObject(generator.outputMode) || typeof generator.outputMode.type !== "string") {
@@ -710,14 +1109,22 @@ function mapOutput(generator, language, index) {
710
1109
  consume(state, [...outputPath, "type"]);
711
1110
  switch (output.type) {
712
1111
  case "downloadFiles":
713
- return finishOutputMapping({ output: { delivery: "zip" } }, output, outputPath, state, index);
1112
+ return finishOutputMapping(
1113
+ { output: { delivery: "zip" } },
1114
+ output,
1115
+ outputPath,
1116
+ state,
1117
+ index,
1118
+ language
1119
+ );
714
1120
  case "github":
715
1121
  return finishOutputMapping(
716
1122
  githubOutput(output, output.publishInfo, rawOutput, language, outputPath, state, index),
717
1123
  output,
718
1124
  outputPath,
719
1125
  state,
720
- index
1126
+ index,
1127
+ language
721
1128
  );
722
1129
  case "githubV2": {
723
1130
  if (!isObject(output.githubV2))
@@ -742,7 +1149,8 @@ function mapOutput(generator, language, index) {
742
1149
  output,
743
1150
  outputPath,
744
1151
  state,
745
- index
1152
+ index,
1153
+ language
746
1154
  );
747
1155
  }
748
1156
  case "publishV2": {
@@ -762,7 +1170,8 @@ function mapOutput(generator, language, index) {
762
1170
  output,
763
1171
  outputPath,
764
1172
  state,
765
- index
1173
+ index,
1174
+ language
766
1175
  );
767
1176
  }
768
1177
  case "publish": {
@@ -782,7 +1191,8 @@ function mapOutput(generator, language, index) {
782
1191
  output,
783
1192
  outputPath,
784
1193
  state,
785
- index
1194
+ index,
1195
+ language
786
1196
  );
787
1197
  }
788
1198
  default:
@@ -856,11 +1266,10 @@ function githubOutput(value, publishInfo, rawOutput, language, sourcePath, state
856
1266
  ...optionalObject("package", { ...publication?.package, ...licensePackage })
857
1267
  };
858
1268
  }
859
- var basicLicenseTypes = { mit: "MIT", apache: "APACHE" };
860
1269
  function mapGithubLicense(value, sourcePath, state) {
861
1270
  if (!isObject(value) || stringValue(value.type) !== "basic") return {};
862
1271
  const id = stringValue(value.id);
863
- const type = id ? basicLicenseTypes[id.toLowerCase()] : void 0;
1272
+ const type = id ? canonicalLicenseType(id) : void 0;
864
1273
  if (!type) return {};
865
1274
  consume(state, [...sourcePath, "type"]);
866
1275
  consume(state, [...sourcePath, "id"]);
@@ -1289,7 +1698,8 @@ function mapAuthors(value, sourcePath, state) {
1289
1698
  });
1290
1699
  return authors;
1291
1700
  }
1292
- function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1701
+ function finishOutputMapping(mapping, outputMode, sourcePath, state, index, language) {
1702
+ const downloadSnippets = mapDownloadSnippets(outputMode, sourcePath, state, language, index);
1293
1703
  for (const path of collectLeafPaths(outputMode, sourcePath)) {
1294
1704
  if (path[path.length - 1] === "_visit") consume(state, path);
1295
1705
  }
@@ -1297,6 +1707,10 @@ function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1297
1707
  const hasCredentials = unsupported.some((diagnostic) => isCredentialPath(diagnostic.path));
1298
1708
  return {
1299
1709
  ...mapping,
1710
+ ...optional(
1711
+ "docs",
1712
+ downloadSnippets === void 0 ? void 0 : { snippets: { enabled: downloadSnippets } }
1713
+ ),
1300
1714
  unsupportedFields: [
1301
1715
  ...state.credentialDiagnostics ?? [],
1302
1716
  ...hasCredentials ? [
@@ -1316,6 +1730,45 @@ function finishOutputMapping(mapping, outputMode, sourcePath, state, index) {
1316
1730
  ]
1317
1731
  };
1318
1732
  }
1733
+ function mapDownloadSnippets(value, sourcePath, state, language, index) {
1734
+ if (!isObject(value)) return void 0;
1735
+ const candidates = [];
1736
+ switch (value.type) {
1737
+ case "downloadFiles":
1738
+ case "github":
1739
+ candidates.push({ value, path: sourcePath });
1740
+ break;
1741
+ case "githubV2":
1742
+ if (isObject(value.githubV2)) {
1743
+ candidates.push({ value: value.githubV2, path: [...sourcePath, "githubV2"] });
1744
+ }
1745
+ break;
1746
+ case "publishV2":
1747
+ if (isObject(value.publishV2)) {
1748
+ candidates.push({ value: value.publishV2, path: [...sourcePath, "publishV2"] });
1749
+ }
1750
+ break;
1751
+ case "publish":
1752
+ if (isObject(value.registryOverrides)) {
1753
+ const registry = defaultRegistry(language, [...sourcePath, "registryOverrides"], index);
1754
+ const override = value.registryOverrides[registry];
1755
+ if (isObject(override)) {
1756
+ candidates.push({
1757
+ value: override,
1758
+ path: [...sourcePath, "registryOverrides", registry]
1759
+ });
1760
+ }
1761
+ }
1762
+ break;
1763
+ }
1764
+ let enabled;
1765
+ for (const candidate of candidates) {
1766
+ if (typeof candidate.value.downloadSnippets !== "boolean") continue;
1767
+ consume(state, [...candidate.path, "downloadSnippets"]);
1768
+ enabled = enabled === true || candidate.value.downloadSnippets;
1769
+ }
1770
+ return enabled;
1771
+ }
1319
1772
  function isCredentialPath(path) {
1320
1773
  const fields = path.filter((part) => typeof part === "string");
1321
1774
  const field = fields[fields.length - 1];
@@ -1383,6 +1836,114 @@ function outputDiagnostic(path, index) {
1383
1836
  suggestedAction: resolvedGuidance?.suggestedAction ?? "Review this output setting and preserve it outside SDK Config when no equivalent exists."
1384
1837
  };
1385
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
+ }
1386
1947
  var OMIT = /* @__PURE__ */ Symbol("omit");
1387
1948
  function inputJsonSchema(schema) {
1388
1949
  return zod.z.toJSONSchema(schema, {
@@ -1640,7 +2201,16 @@ var sdkConfigV1PublishConfigSchema = zod.z.discriminatedUnion("registry", [
1640
2201
  zod.z.strictObject({
1641
2202
  registry: zod.z.literal("npm").describe("Publishes the package to an npm-compatible registry."),
1642
2203
  token: nonEmptyStringSchema.optional().describe("The npm registry token, or an environment expression that resolves to it."),
2204
+ trustedPublishing: zod.z.boolean().optional().describe("Whether npm publication uses trusted publishing (OIDC) instead of a token."),
1643
2205
  ...commonPublishShape
2206
+ }).superRefine((publish, context) => {
2207
+ if (publish.trustedPublishing === true && publish.token !== void 0) {
2208
+ context.addIssue({
2209
+ code: "custom",
2210
+ message: "token must be omitted when trustedPublishing is true",
2211
+ path: ["token"]
2212
+ });
2213
+ }
1644
2214
  }),
1645
2215
  zod.z.strictObject({
1646
2216
  registry: zod.z.literal("pypi").describe("Publishes the package to a PyPI-compatible registry."),
@@ -1718,10 +2288,29 @@ var sdkConfigV1OutputConfigSchema = zod.z.discriminatedUnion(
1718
2288
  [filesOutputSchema, zipOutputSchema, githubDeliverySchema],
1719
2289
  { error: 'output.delivery must be one of "files", "zip", or "github"' }
1720
2290
  );
1721
-
1722
- // src/sdk-config/v1/package.ts
1723
- var sdkConfigV1DependencySchema = dependencySchema;
1724
- var sdkConfigV1PackageConfigSchema = packageConfigSchema;
2291
+ var cliDistributionShape = {
2292
+ distribution: cliDistributionConfigSchema.optional().describe(
2293
+ "CLI release channels published by the generated release workflow; credentials are GitHub Actions secret names."
2294
+ )
2295
+ };
2296
+ function rejectDistributionWithoutGithub(output, context) {
2297
+ if (output.distribution !== void 0) {
2298
+ context.addIssue({
2299
+ code: "custom",
2300
+ message: CLI_DISTRIBUTION_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2301
+ path: ["distribution"]
2302
+ });
2303
+ }
2304
+ }
2305
+ var sdkConfigV1CliOutputConfigSchema = zod.z.discriminatedUnion(
2306
+ "delivery",
2307
+ [
2308
+ filesOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2309
+ zipOutputSchema.extend(cliDistributionShape).superRefine(rejectDistributionWithoutGithub),
2310
+ githubDeliverySchema.extend(cliDistributionShape)
2311
+ ],
2312
+ { error: 'output.delivery must be one of "files", "zip", or "github"' }
2313
+ );
1725
2314
  var sdkConfigV1ReplayConfigSchema = zod.z.strictObject({
1726
2315
  enabled: zod.z.boolean().describe("Whether regeneration reapplies customer-authored repository changes.")
1727
2316
  });
@@ -1798,10 +2387,6 @@ var sdkConfigV1SourceConfigSchema = zod.z.strictObject({
1798
2387
  seenIds.add(id);
1799
2388
  });
1800
2389
  });
1801
- var cliGenerationConfigSchema = zod.z.strictObject({
1802
- paginationParameters: zod.z.array(nonEmptyStringSchema).optional().describe("Request parameter names treated as pagination controls by the CLI."),
1803
- skills: zod.z.boolean().optional().describe("Whether the generated CLI includes skills that teach AI agents to invoke commands.")
1804
- });
1805
2390
  var csharpGenerationConfigSchema = zod.z.strictObject({
1806
2391
  useOptionalWrapper: zod.z.boolean().optional().describe("Whether optional values use an explicit Optional wrapper."),
1807
2392
  simplifyObjectDictionaries: zod.z.boolean().optional().describe("Whether object schemas with arbitrary values use simplified dictionary types."),
@@ -2054,7 +2639,10 @@ var sdkConfigV1TargetSchema = zod.z.discriminatedUnion("language", [
2054
2639
  zod.z.strictObject({
2055
2640
  language: zod.z.literal("cli").describe("Generates a command-line interface."),
2056
2641
  generation: sdkConfigV1GenerationConfigOverrideSchema.extend(cliGenerationConfigSchema.shape).optional().describe("Common and CLI-specific generation settings for this target."),
2057
- ...targetOverrideShape
2642
+ ...targetOverrideShape,
2643
+ output: sdkConfigV1CliOutputConfigSchema.optional().describe(
2644
+ "Output configuration, including optional CLI distribution channels, that replaces the root output for this target."
2645
+ )
2058
2646
  }),
2059
2647
  zod.z.strictObject({
2060
2648
  language: zod.z.literal("mcp").describe("Generates an MCP server."),
@@ -2071,7 +2659,7 @@ var sdkConfigV1TargetSchema = zod.z.discriminatedUnion("language", [
2071
2659
  // src/sdk-config/v1/sdk-config-v1.ts
2072
2660
  var SDK_CONFIG_V1_SCHEMA_VERSION = "sdk-config/v1";
2073
2661
  var publishRegistryLanguages = {
2074
- npm: ["typescript", "mcp"],
2662
+ npm: ["typescript", "mcp", "cli"],
2075
2663
  pypi: ["python"],
2076
2664
  maven: ["java", "kotlin"],
2077
2665
  nuget: ["csharp"],
@@ -2148,6 +2736,13 @@ function validateTargetPublishing(target, targetIndex, globalPackage, globalOutp
2148
2736
  });
2149
2737
  return;
2150
2738
  }
2739
+ if (target.language === "cli" && output.delivery !== "github") {
2740
+ context.addIssue({
2741
+ code: "custom",
2742
+ message: CLI_PUBLISH_REQUIRES_GITHUB_DELIVERY_MESSAGE,
2743
+ path: target.output ? ["targets", targetIndex, "output", "delivery"] : ["output", "delivery"]
2744
+ });
2745
+ }
2151
2746
  validatePublishingIdentity(
2152
2747
  { ...globalPackage, ...target.package },
2153
2748
  registry,
@@ -2239,11 +2834,12 @@ function mapFernConfigToSdkConfigV1(input) {
2239
2834
  generator,
2240
2835
  language,
2241
2836
  invocation,
2242
- ...outputMapping
2837
+ ...outputMapping,
2838
+ docs: { ...invocation.docs, ...outputMapping.docs }
2243
2839
  };
2244
2840
  });
2245
2841
  const clients = partitionSharedBlock(mapped.map(({ invocation }) => invocation.client));
2246
- const docs = partitionSharedBlock(mapped.map(({ invocation }) => invocation.docs));
2842
+ const docs = partitionSharedBlock(mapped.map(({ docs: docs2 }) => docs2));
2247
2843
  const generations = partitionSharedBlock(mapped.map(({ invocation }) => invocation.generation));
2248
2844
  const api = { ...input.api ?? {} };
2249
2845
  delete api.audiences;
@@ -2259,16 +2855,28 @@ function mapFernConfigToSdkConfigV1(input) {
2259
2855
  package: outputPackage,
2260
2856
  generation: outputGeneration
2261
2857
  }, index) => {
2858
+ const distribution = applyCliDistribution(output, invocation.cliDistribution, index);
2859
+ invocation.unsupportedFields.push(...distribution.diagnostics);
2262
2860
  const target = {
2263
2861
  language,
2264
- output,
2862
+ output: distribution.output,
2265
2863
  ...optional("sdkName", generator.sdkName),
2266
2864
  ...optional("sdkVersion", generator.sdkVersion),
2267
2865
  ...optional("client", clients.targetOverrides[index]),
2268
2866
  ...optional("docs", docs.targetOverrides[index])
2269
2867
  };
2270
- if (Object.keys(invocation.package).length > 0 || outputPackage || generator.package) {
2271
- target.package = { ...invocation.package, ...outputPackage, ...generator.package };
2868
+ const targetPackage = { ...invocation.package, ...outputPackage, ...generator.package };
2869
+ invocation.unsupportedFields.push(
2870
+ ...resolveTargetPackage(
2871
+ targetPackage,
2872
+ invocation.packageFallbacks,
2873
+ generator,
2874
+ output.delivery,
2875
+ index
2876
+ )
2877
+ );
2878
+ if (Object.keys(targetPackage).length > 0 || outputPackage || generator.package) {
2879
+ target.package = targetPackage;
2272
2880
  }
2273
2881
  const targetGeneration = {
2274
2882
  ...generations.targetOverrides[index],
@@ -2450,10 +3058,14 @@ function mapInvocation(generator, language, activeLanguages, index) {
2450
3058
  ...optional("smartCasingDigitWordBoundary", smartCasingDigitWordBoundary)
2451
3059
  };
2452
3060
  }
2453
- const targetGeneration = mapLanguageConfig(language, config, state, packageConfig, [
2454
- ...prefix,
2455
- "config"
2456
- ]);
3061
+ const targetGeneration = mapLanguageConfig(
3062
+ language,
3063
+ config,
3064
+ state,
3065
+ packageConfig,
3066
+ [...prefix, "config"],
3067
+ index
3068
+ );
2457
3069
  mapPublishMetadata(generator.publishMetadata, packageConfig);
2458
3070
  if (generator.keywords?.length) {
2459
3071
  generation.reservedKeywords = [...generator.keywords];
@@ -2470,12 +3082,22 @@ function mapInvocation(generator, language, activeLanguages, index) {
2470
3082
  }
2471
3083
  const docs = mapReadme(generator.readme, language, activeLanguages, state, [...prefix, "readme"]);
2472
3084
  const unsupportedFields = [
3085
+ ...state.valueDiagnostics ?? [],
2473
3086
  ...collectUnsupported(config, [...prefix, "config"], state),
2474
3087
  ...settings ? collectUnsupported(settings, [...prefix, "settings"], state) : [],
2475
3088
  ...isObject(generator.readme) ? collectUnsupported(generator.readme, [...prefix, "readme"], state) : [],
2476
3089
  ...unsupportedResolvedFields(generator, index, apiWideIdempotency !== void 0)
2477
3090
  ];
2478
- return { client, docs, generation, package: packageConfig, targetGeneration, unsupportedFields };
3091
+ return {
3092
+ client,
3093
+ docs,
3094
+ generation,
3095
+ package: packageConfig,
3096
+ packageFallbacks: state.packageFallbacks ?? [],
3097
+ ...optional("cliDistribution", state.cliDistribution),
3098
+ targetGeneration,
3099
+ unsupportedFields
3100
+ };
2479
3101
  }
2480
3102
  function unsupportedResolvedFields(generator, index, idempotencyMapped) {
2481
3103
  const values = [
@@ -2665,6 +3287,7 @@ function mapCommonConfig(language, config, state, client, generation, packageCon
2665
3287
  const packagePath = takeString(config, ["packagePath"], state, basePath);
2666
3288
  if (packagePath !== void 0) generation.layout = { packagePath };
2667
3289
  mapDependencies(config, state, packageConfig, basePath);
3290
+ mapPeerDependenciesMeta(config, state, packageConfig, basePath);
2668
3291
  }
2669
3292
  function mapTypescriptStreams(config, state, basePath) {
2670
3293
  const responseType = takeEnum(config, ["streamType"], ["wrapper", "web"], state, basePath);
@@ -2678,7 +3301,7 @@ function mapTypescriptStreams(config, state, basePath) {
2678
3301
  if (responseType === void 0 && fileResponseType === void 0) return void 0;
2679
3302
  return { enabled: true, ...compact({ responseType, fileResponseType }) };
2680
3303
  }
2681
- function mapLanguageConfig(language, config, state, packageConfig, basePath) {
3304
+ function mapLanguageConfig(language, config, state, packageConfig, basePath, targetIndex) {
2682
3305
  switch (language) {
2683
3306
  case "typescript":
2684
3307
  return mapTypescript(config, state, packageConfig, basePath);
@@ -2705,7 +3328,7 @@ function mapLanguageConfig(language, config, state, packageConfig, basePath) {
2705
3328
  case "swift":
2706
3329
  return mapSwift(config, state, basePath);
2707
3330
  case "cli":
2708
- return mapCli(config, state, packageConfig, basePath);
3331
+ return mapCli(config, state, packageConfig, basePath, targetIndex);
2709
3332
  case "terraform":
2710
3333
  return mapTerraform(config, state, packageConfig, basePath);
2711
3334
  }
@@ -2722,6 +3345,7 @@ function mapTypescript(config, state, packageConfig, basePath) {
2722
3345
  const packageManagerAtIndex = packageJsonPackageManager ? packageJsonPackageManager.indexOf("@", packageJsonPackageManager.startsWith("@") ? 1 : 0) : -1;
2723
3346
  const packageManagerVersionPart = packageManagerAtIndex >= 0 ? packageJsonPackageManager?.slice(packageManagerAtIndex + 1).split("+")[0] : void 0;
2724
3347
  const packageManagerVersion = packageManagerVersionPart || void 0;
3348
+ if (packageJsonManifest) liftPackageJsonDependencies(packageJsonManifest, state, packageConfig);
2725
3349
  const serdeLayer = takeBoolean(config, ["serdeLayer"], state, basePath);
2726
3350
  const noSerdeLayer = takeBoolean(config, ["noSerdeLayer"], state, basePath);
2727
3351
  const fetchSupport = takeEnum(config, ["fetchSupport"], ["native"], state, basePath);
@@ -2778,7 +3402,8 @@ function mapPython(config, state, packageConfig, basePath) {
2778
3402
  });
2779
3403
  }
2780
3404
  function mapJvm(language, config, state, packageConfig, basePath) {
2781
- const namespace = takeString(config, ["packageName", "packagePrefix"], state, basePath);
3405
+ const namespaceAliases = language === "java" ? ["packagePrefix"] : ["packageName", "packagePrefix"];
3406
+ const namespace = takeString(config, namespaceAliases, state, basePath);
2782
3407
  const groupId = takeString(config, ["group", "groupId"], state, basePath);
2783
3408
  const artifactId = takeString(config, ["artifact", "artifactId"], state, basePath);
2784
3409
  if (namespace !== void 0) packageConfig.namespace = namespace;
@@ -2890,6 +3515,7 @@ function mapRust(config, state, packageConfig, basePath) {
2890
3515
  const description = takeString(config, ["packageDescription"], state, basePath);
2891
3516
  const documentationUrl = takeString(config, ["packageDocumentation"], state, basePath);
2892
3517
  Object.assign(packageConfig, compact({ packageName, repository, description, documentationUrl }));
3518
+ mapLicenseFallback(config, ["packageLicense"], state, basePath);
2893
3519
  return compact({
2894
3520
  dateTimeType: takeEnum(config, ["dateTimeType"], ["offset", "utc"], state, basePath),
2895
3521
  capitalizeInitialisms: takeBoolean(config, ["capitalizeInitialisms"], state, basePath),
@@ -2903,7 +3529,7 @@ function mapSwift(config, state, basePath) {
2903
3529
  nullableAsOptional: takeBoolean(config, ["nullableAsOptional"], state, basePath)
2904
3530
  });
2905
3531
  }
2906
- function mapCli(config, state, packageConfig, basePath) {
3532
+ function mapCli(config, state, packageConfig, basePath, targetIndex) {
2907
3533
  const identity = takeObject(config, ["packageIdentity"], state, basePath);
2908
3534
  if (identity) {
2909
3535
  Object.assign(
@@ -2914,10 +3540,13 @@ function mapCli(config, state, packageConfig, basePath) {
2914
3540
  description: takeString(identity.value, ["description"], state, identity.path)
2915
3541
  })
2916
3542
  );
3543
+ mapCliPackageIdentity(identity, state, targetIndex);
2917
3544
  }
3545
+ mapCliDistribution(config, state, basePath, targetIndex);
2918
3546
  return compact({
2919
3547
  paginationParameters: takeStringArray(config, ["paginationParameters"], state, basePath),
2920
- skills: takeBoolean(config, ["skills"], state, basePath)
3548
+ skills: takeBoolean(config, ["skills"], state, basePath),
3549
+ ...mapCliGeneration(config, state, basePath, targetIndex)
2921
3550
  });
2922
3551
  }
2923
3552
  function mapTerraform(config, state, packageConfig, basePath) {
@@ -3001,6 +3630,48 @@ function mapDependencies(config, state, packageConfig, basePath) {
3001
3630
  if (dependencies.length) packageConfig[field] = dependencies;
3002
3631
  }
3003
3632
  }
3633
+ function liftPackageJsonDependencies(manifest, state, packageConfig) {
3634
+ for (const [field, target] of [
3635
+ ["dependencies", "extraDependencies"],
3636
+ ["devDependencies", "extraDevDependencies"],
3637
+ ["peerDependencies", "extraPeerDependencies"]
3638
+ ]) {
3639
+ const located = takeObject(manifest.value, [field], state, manifest.path);
3640
+ if (!located) continue;
3641
+ const lifted = Object.entries(located.value).flatMap(
3642
+ ([name, dependency]) => mapDependency(name, dependency, state, [...located.path, name])
3643
+ );
3644
+ if (lifted.length) packageConfig[target] = overrideByName(packageConfig[target] ?? [], lifted);
3645
+ }
3646
+ const meta = takeObject(manifest.value, ["peerDependenciesMeta"], state, manifest.path);
3647
+ if (!meta) return;
3648
+ const entries = peerDependenciesMetaEntries(meta, state);
3649
+ if (entries.length) {
3650
+ packageConfig.extraPeerDependenciesMeta = {
3651
+ ...packageConfig.extraPeerDependenciesMeta,
3652
+ ...Object.fromEntries(entries)
3653
+ };
3654
+ }
3655
+ }
3656
+ function overrideByName(existing, overrides) {
3657
+ const byName = new Map(existing.map((dependency) => [dependency.name, dependency]));
3658
+ overrides.forEach((dependency) => byName.set(dependency.name, dependency));
3659
+ return [...byName.values()];
3660
+ }
3661
+ function mapPeerDependenciesMeta(config, state, packageConfig, basePath) {
3662
+ const located = takeObject(config, ["extraPeerDependenciesMeta"], state, basePath);
3663
+ if (!located) return;
3664
+ const entries = peerDependenciesMetaEntries(located, state);
3665
+ if (entries.length) packageConfig.extraPeerDependenciesMeta = Object.fromEntries(entries);
3666
+ }
3667
+ function peerDependenciesMetaEntries(located, state) {
3668
+ return Object.entries(located.value).flatMap(([name, value]) => {
3669
+ const parsed = jsonObjectSchema.safeParse(value);
3670
+ if (!parsed.success) return [];
3671
+ consume(state, [...located.path, name]);
3672
+ return [[name, parsed.data]];
3673
+ });
3674
+ }
3004
3675
  function mapDependency(name, value, state, path) {
3005
3676
  if (typeof value === "string" && value) {
3006
3677
  consume(state, path);
@@ -3008,13 +3679,7 @@ function mapDependency(name, value, state, path) {
3008
3679
  }
3009
3680
  if (!isObject(value)) return [];
3010
3681
  const version = takeString(value, ["version"], state, path);
3011
- const gitUrl = takeString(value, ["git"], state, path);
3012
- const localPath = takeString(value, ["path"], state, path);
3013
- const source = gitUrl ? {
3014
- type: "git",
3015
- url: gitUrl,
3016
- ...optional("ref", takeString(value, ["ref"], state, path))
3017
- } : localPath ? { type: "path", path: localPath } : void 0;
3682
+ const source = takeDependencySource(value, state, path);
3018
3683
  if (!version && !source) return [];
3019
3684
  return [
3020
3685
  {
@@ -3030,6 +3695,17 @@ function mapDependency(name, value, state, path) {
3030
3695
  }
3031
3696
  ];
3032
3697
  }
3698
+ function takeDependencySource(value, state, path) {
3699
+ const gitUrl = takeString(value, ["git"], state, path);
3700
+ if (gitUrl) {
3701
+ const ref = takeString(value, ["ref", "rev", "branch"], state, path);
3702
+ return { type: "git", url: gitUrl, ...optional("ref", ref) };
3703
+ }
3704
+ const localPath = takeString(value, ["path"], state, path);
3705
+ if (localPath) return { type: "path", path: localPath };
3706
+ const registry = takeString(value, ["registry"], state, path);
3707
+ return registry ? { type: "registry", registry } : void 0;
3708
+ }
3033
3709
  function takeCustomSections(value, language, activeLanguages, state, basePath) {
3034
3710
  const located = locate(value, ["customSections"], basePath);
3035
3711
  if (!located || !Array.isArray(located.value)) return void 0;
@@ -3189,14 +3865,21 @@ function takeToolsets(value, aliases, state, basePath) {
3189
3865
  }
3190
3866
 
3191
3867
  exports.FernConfigMappingError = FernConfigMappingError;
3868
+ exports.SDK_CONFIG_V1_CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE = CLI_DISTRIBUTION_NON_RELEASE_MODE_CODE;
3192
3869
  exports.SDK_CONFIG_V1_SCHEMA_VERSION = SDK_CONFIG_V1_SCHEMA_VERSION;
3870
+ exports.getSdkConfigV1Diagnostics = getSdkConfigV1Diagnostics;
3193
3871
  exports.mapFernConfigToSdkConfigV1 = mapFernConfigToSdkConfigV1;
3194
3872
  exports.parseSdkConfigV1 = parseSdkConfigV1;
3195
3873
  exports.parseSdkConfigV1ForConsumption = parseSdkConfigV1ForConsumption;
3196
3874
  exports.sdkConfigV1ApiConfigSchema = sdkConfigV1ApiConfigSchema;
3197
3875
  exports.sdkConfigV1AuthConfigSchema = sdkConfigV1AuthConfigSchema;
3198
3876
  exports.sdkConfigV1AuthSchemeSchema = sdkConfigV1AuthSchemeSchema;
3877
+ exports.sdkConfigV1CliDistributionConfigSchema = cliDistributionConfigSchema;
3878
+ exports.sdkConfigV1CliDistributionGithubAppSchema = cliDistributionGithubAppSchema;
3879
+ exports.sdkConfigV1CliDistributionHomebrewSchema = cliDistributionHomebrewSchema;
3880
+ exports.sdkConfigV1CliDistributionScoopSchema = cliDistributionScoopSchema;
3199
3881
  exports.sdkConfigV1CliGenerationConfigSchema = cliGenerationConfigSchema;
3882
+ exports.sdkConfigV1CliOutputConfigSchema = sdkConfigV1CliOutputConfigSchema;
3200
3883
  exports.sdkConfigV1ClientConfigOverrideSchema = sdkConfigV1ClientConfigOverrideSchema;
3201
3884
  exports.sdkConfigV1ClientConfigSchema = sdkConfigV1ClientConfigSchema;
3202
3885
  exports.sdkConfigV1ComposerPackageNameSchema = composerPackageNameSchema;
@@ -3206,6 +3889,7 @@ exports.sdkConfigV1DocsConfigSchema = sdkConfigV1DocsConfigSchema;
3206
3889
  exports.sdkConfigV1ExactSemverSchema = exactSemverSchema;
3207
3890
  exports.sdkConfigV1GenerationConfigOverrideSchema = sdkConfigV1GenerationConfigOverrideSchema;
3208
3891
  exports.sdkConfigV1GenerationConfigSchema = sdkConfigV1GenerationConfigSchema;
3892
+ exports.sdkConfigV1GithubActionsSecretNameSchema = githubActionsSecretNameSchema;
3209
3893
  exports.sdkConfigV1GoGenerationConfigSchema = goGenerationConfigSchema;
3210
3894
  exports.sdkConfigV1GoModulePathSchema = goModulePathSchema;
3211
3895
  exports.sdkConfigV1JavaGenerationConfigSchema = javaGenerationConfigSchema;