@cerios/salesforce-sobjectly 1.1.0 → 1.2.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.
@@ -1,4 +1,4 @@
1
- const require_sf_cli = require("./sf-cli-R6LHwqoo.cjs");
1
+ const require_sf_cli = require("./sf-cli-S2BrCbik.cjs");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  let node_fs_promises = require("node:fs/promises");
@@ -444,15 +444,28 @@ var CodegenConfigError = class extends Error {
444
444
  this.problems = problems;
445
445
  }
446
446
  };
447
- /** The env-variable options each env-based auth type accepts. */
447
+ /** The options each auth type accepts: its credential keys, then the deprecated `*Env` keys. */
448
448
  const AUTH_OPTIONS = {
449
449
  clientCredentials: [
450
+ "loginUrl",
451
+ "clientId",
452
+ "clientSecret",
450
453
  "loginUrlEnv",
451
454
  "clientIdEnv",
452
455
  "clientSecretEnv"
453
456
  ],
454
- accessToken: ["accessTokenEnv", "instanceUrlEnv"],
457
+ accessToken: [
458
+ "accessToken",
459
+ "instanceUrl",
460
+ "accessTokenEnv",
461
+ "instanceUrlEnv"
462
+ ],
455
463
  jwtBearer: [
464
+ "loginUrl",
465
+ "clientId",
466
+ "username",
467
+ "privateKey",
468
+ "privateKeyPath",
456
469
  "loginUrlEnv",
457
470
  "clientIdEnv",
458
471
  "usernameEnv",
@@ -461,6 +474,17 @@ const AUTH_OPTIONS = {
461
474
  ],
462
475
  sfCli: ["targetOrg"]
463
476
  };
477
+ /** The deprecated `*Env` auth options, each mapped to the credential key that replaces it. */
478
+ const DEPRECATED_AUTH_OPTIONS = {
479
+ loginUrlEnv: "loginUrl",
480
+ clientIdEnv: "clientId",
481
+ clientSecretEnv: "clientSecret",
482
+ accessTokenEnv: "accessToken",
483
+ instanceUrlEnv: "instanceUrl",
484
+ usernameEnv: "username",
485
+ privateKeyEnv: "privateKey",
486
+ privateKeyPathEnv: "privateKeyPath"
487
+ };
464
488
  const PICKLIST_MODES = [
465
489
  "union",
466
490
  "string",
@@ -572,8 +596,17 @@ function validateAuth(value, { json, problem }) {
572
596
  problem(`auth.type: must be one of ${Object.keys(AUTH_OPTIONS).join(", ")}, got ${show(type)}.`);
573
597
  return;
574
598
  }
575
- for (const [key, option] of Object.entries(rest)) if (!allowed.includes(key)) problem(`auth.${key}: not an option of "${String(type)}". Valid options: ${allowed.join(", ")}.`);
576
- else if (typeof option !== "string" || option.length === 0) problem(`auth.${key}: must be a non-empty string, got ${show(option)}.`);
599
+ for (const [key, option] of Object.entries(rest)) if (!allowed.includes(key)) {
600
+ const valid = allowed.filter((name) => !(name in DEPRECATED_AUTH_OPTIONS));
601
+ problem(`auth.${key}: not an option of "${String(type)}". Valid options: ${valid.join(", ")}.`);
602
+ } else validateAuthOption(key, option, rest, problem);
603
+ }
604
+ function validateAuthOption(key, option, setting, problem) {
605
+ const replacement = DEPRECATED_AUTH_OPTIONS[key];
606
+ if (replacement !== void 0 && replacement in setting) problem(`auth.${key}: use either ${replacement} or ${key}, not both.`);
607
+ else if (replacement !== void 0) {
608
+ if (typeof option !== "string" || option.length === 0) problem(`auth.${key}: must be a non-empty string, got ${show(option)}.`);
609
+ } else if (option !== void 0 && typeof option !== "string") problem(`auth.${key}: must be a string, got ${show(option)}.`);
577
610
  }
578
611
  function show(value) {
579
612
  if (value === void 0) return "undefined";
@@ -585,24 +618,6 @@ function show(value) {
585
618
  }
586
619
  }
587
620
  //#endregion
588
- //#region src/codegen/config.ts
589
- /**
590
- * Type-checks a `sobjectly.config.ts`. The listed `sobjects` become a literal union, so a typo in
591
- * a per-sObject option is a compile error:
592
- *
593
- * ```ts
594
- * export default defineConfig({
595
- * apiVersion: "v66.0",
596
- * output: "src/generated/sobjects.ts",
597
- * sobjects: ["Account", "Contact"],
598
- * excludeCreateFields: { Acount: ["Name"] }, // ❌ "Acount" is not in sobjects
599
- * });
600
- * ```
601
- */
602
- function defineConfig(config) {
603
- return config;
604
- }
605
- //#endregion
606
621
  //#region src/codegen/load-config.ts
607
622
  /** Config file names, in lookup order. */
608
623
  const CONFIG_FILE_NAMES = [
@@ -654,25 +669,50 @@ function readJson(path) {
654
669
  }
655
670
  }
656
671
  //#endregion
672
+ //#region src/codegen/config.ts
673
+ /**
674
+ * Type-checks a `sobjectly.config.ts`. The listed `sobjects` become a literal union, so a typo in
675
+ * a per-sObject option is a compile error:
676
+ *
677
+ * ```ts
678
+ * export default defineConfig({
679
+ * apiVersion: "v66.0",
680
+ * output: "src/generated/sobjects.ts",
681
+ * sobjects: ["Account", "Contact"],
682
+ * excludeCreateFields: { Acount: ["Name"] }, // ❌ "Acount" is not in sobjects
683
+ * });
684
+ * ```
685
+ */
686
+ function defineConfig(config) {
687
+ return config;
688
+ }
689
+ //#endregion
657
690
  //#region src/codegen/init.ts
658
691
  const SOBJECT_NAME = /^[A-Za-z][A-Za-z0-9_]*$/;
659
692
  const NPM_SCRIPT = "sobjects:generate";
660
- /** The environment variables each auth type reads by default. */
661
- const AUTH_ENV_VARS = {
693
+ /** The credential keys `init` writes per auth type, each with the environment variable it suggests. */
694
+ const AUTH_FIELDS = {
662
695
  clientCredentials: [
663
- "SF_LOGIN_URL",
664
- "SF_CLIENT_ID",
665
- "SF_CLIENT_SECRET"
696
+ ["loginUrl", "SF_LOGIN_URL"],
697
+ ["clientId", "SF_CLIENT_ID"],
698
+ ["clientSecret", "SF_CLIENT_SECRET"]
666
699
  ],
667
- accessToken: ["SF_ACCESS_TOKEN", "SF_INSTANCE_URL"],
700
+ accessToken: [["accessToken", "SF_ACCESS_TOKEN"], ["instanceUrl", "SF_INSTANCE_URL"]],
668
701
  jwtBearer: [
669
- "SF_LOGIN_URL",
670
- "SF_CLIENT_ID",
671
- "SF_USERNAME",
672
- "SF_PRIVATE_KEY_PATH"
702
+ ["loginUrl", "SF_LOGIN_URL"],
703
+ ["clientId", "SF_CLIENT_ID"],
704
+ ["username", "SF_USERNAME"],
705
+ ["privateKeyPath", "SF_PRIVATE_KEY_PATH"]
673
706
  ],
674
707
  sfCli: []
675
708
  };
709
+ /** The environment variables the config written by `init` reads, per auth type. */
710
+ const AUTH_ENV_VARS = {
711
+ clientCredentials: AUTH_FIELDS.clientCredentials.map(([, envName]) => envName),
712
+ accessToken: AUTH_FIELDS.accessToken.map(([, envName]) => envName),
713
+ jwtBearer: AUTH_FIELDS.jwtBearer.map(([, envName]) => envName),
714
+ sfCli: []
715
+ };
676
716
  const AUTH_CHOICES = [
677
717
  {
678
718
  value: "clientCredentials",
@@ -831,7 +871,6 @@ function renderJsonConfig(answers) {
831
871
  return `${JSON.stringify(config, null, " ")}\n`;
832
872
  }
833
873
  function renderTypeScriptConfig(answers) {
834
- const envVars = AUTH_ENV_VARS[answers.auth];
835
874
  const sobjects = answers.sobjects.map((name) => JSON.stringify(name)).join(", ");
836
875
  return [
837
876
  "import { defineConfig } from \"@cerios/salesforce-sobjectly/codegen\";",
@@ -843,26 +882,38 @@ function renderTypeScriptConfig(answers) {
843
882
  `\toutput: ${JSON.stringify(answers.output)},`,
844
883
  " // The sObjects to generate types for.",
845
884
  `\tsobjects: [${sobjects}],`,
846
- `\t// ${authComment(answers.auth, envVars)}`,
885
+ `\t// ${authComment(answers.auth)}`,
847
886
  `\tauth: ${renderAuth(answers)},`,
848
887
  `\tpicklists: ${JSON.stringify(answers.picklists)},`,
849
888
  "});",
850
889
  ""
851
890
  ].join("\n");
852
891
  }
892
+ /** The JSON auth setting: credentials are `"${NAME}"` placeholders, read from the environment. */
853
893
  function authSetting(answers) {
854
- return answers.auth === "sfCli" && answers.targetOrg ? {
894
+ if (answers.auth === "sfCli") return answers.targetOrg ? {
855
895
  type: "sfCli",
856
896
  targetOrg: answers.targetOrg
857
- } : { type: answers.auth };
897
+ } : { type: "sfCli" };
898
+ const fields = AUTH_FIELDS[answers.auth].map(([key, envName]) => [key, `\${${envName}}`]);
899
+ return {
900
+ type: answers.auth,
901
+ ...Object.fromEntries(fields)
902
+ };
858
903
  }
904
+ /** The TypeScript auth setting: credentials are read with `process.env`. */
859
905
  function renderAuth(answers) {
860
- const setting = authSetting(answers);
861
- const targetOrg = setting.targetOrg ? `, targetOrg: ${JSON.stringify(setting.targetOrg)}` : "";
862
- return `{ type: ${JSON.stringify(setting.type)}${targetOrg} }`;
906
+ if (answers.auth === "sfCli") return `{ type: "sfCli"${answers.targetOrg ? `, targetOrg: ${JSON.stringify(answers.targetOrg)}` : ""} }`;
907
+ const fields = AUTH_FIELDS[answers.auth].map(([key, envName]) => `\t\t${key}: process.env.${envName},`);
908
+ return [
909
+ "{",
910
+ `\t\ttype: ${JSON.stringify(answers.auth)},`,
911
+ ...fields,
912
+ " }"
913
+ ].join("\n");
863
914
  }
864
- function authComment(auth, envVars) {
865
- return auth === "sfCli" ? "Uses an org you are logged into with the Salesforce CLI (sf org login web)." : `Reads ${formatList(envVars)} from the environment.`;
915
+ function authComment(auth) {
916
+ return auth === "sfCli" ? "Uses an org you are logged into with the Salesforce CLI (sf org login web)." : "Fill these in from process.env (any variable names), a secret store or elsewhere. Keep secrets out of this file.";
866
917
  }
867
918
  async function maybeUpdateEnvExample(options, auth) {
868
919
  const path = (0, node_path.join)(options.cwd, ".env.example");
@@ -912,9 +963,10 @@ function printNextSteps(log, answers, scriptAdded, cwd) {
912
963
  "Next steps:",
913
964
  cli ? ` 1. Log in with the Salesforce CLI: sf org login web${answers.targetOrg ? ` --alias ${answers.targetOrg}` : " --set-default"}` : ` 1. Put ${formatList(AUTH_ENV_VARS[answers.auth])} in a .env file${envIgnored ? "" : " (and add .env to .gitignore)"}.`,
914
965
  ` 2. Generate the types: ${command}`,
915
- " 3. Use them:",
966
+ " 3. Use them, logging in with the config's auth:",
967
+ " import { loadAuth } from \"@cerios/salesforce-sobjectly/codegen\";",
916
968
  ` import { API_VERSION, type SObjectRegistry } from "./${answers.output.replace(/\.(ts|mts|cts)$/, "")}";`,
917
- " const sf = new SalesforceClient<SObjectRegistry>({ apiVersion: API_VERSION, auth });"
969
+ " const sf = new SalesforceClient<SObjectRegistry>({ apiVersion: API_VERSION, auth: await loadAuth() });"
918
970
  ].join("\n"));
919
971
  }
920
972
  function formatList(items) {
@@ -1081,7 +1133,7 @@ async function buildSource(input, options) {
1081
1133
  const env = options.env ?? process.env;
1082
1134
  const outputPath = (0, node_path.isAbsolute)(config.output) ? config.output : (0, node_path.resolve)(options.cwd ?? process.cwd(), config.output);
1083
1135
  const client = new require_sf_cli.SalesforceClient({
1084
- auth: resolveAuth(config.auth, env),
1136
+ auth: resolveAuth(config.auth, env, { warn: (message) => logger.warn(message) }),
1085
1137
  apiVersion,
1086
1138
  transport: config.transport,
1087
1139
  retry: true
@@ -1134,39 +1186,118 @@ function normalizeSource(source) {
1134
1186
  }
1135
1187
  return result;
1136
1188
  }
1137
- /** Turns the config's auth setting into an auth provider, reading env-based credentials. */
1138
- function resolveAuth(auth, env) {
1189
+ /** Where the JWT private key comes from, in order of preference, with each default variable. */
1190
+ const PRIVATE_KEY_SOURCES = [["privateKey", "SF_PRIVATE_KEY"], ["privateKeyPath", "SF_PRIVATE_KEY_PATH"]];
1191
+ /** A `"${NAME}"` placeholder. Only a whole value counts, so a secret that contains `${` is kept as-is. */
1192
+ const ENV_PLACEHOLDER = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
1193
+ /**
1194
+ * Turns the config's auth setting into an auth provider. Each credential comes from its key in
1195
+ * the setting (a `"${NAME}"` placeholder is read from `env`), else from the variable a deprecated
1196
+ * `*Env` key names, else from its default `SF_*` variable. Throws one error listing every
1197
+ * missing credential.
1198
+ */
1199
+ function resolveAuth(auth, env, options = {}) {
1139
1200
  const setting = auth ?? { type: "clientCredentials" };
1140
1201
  if ("getToken" in setting) return setting;
1141
- const read = (name) => {
1142
- const value = env[name];
1143
- if (!value) throw new Error(`Environment variable ${name} is not set.`);
1202
+ const problems = [];
1203
+ const lookup = (key, defaultEnv) => readCredential(setting, key, defaultEnv, env, options.warn);
1204
+ const read = (key, defaultEnv) => {
1205
+ const { value, problem } = lookup(key, defaultEnv);
1206
+ if (problem) problems.push(problem);
1144
1207
  return value;
1145
1208
  };
1146
1209
  switch (setting.type) {
1147
- case "accessToken": return require_sf_cli.accessToken({
1148
- accessToken: read(setting.accessTokenEnv ?? "SF_ACCESS_TOKEN"),
1149
- instanceUrl: read(setting.instanceUrlEnv ?? "SF_INSTANCE_URL")
1150
- });
1151
- case "jwtBearer": return jwtBearerFromEnv(setting, env, read);
1152
- case "sfCli": return require_sf_cli.sfCli({ targetOrg: setting.targetOrg });
1153
- case "clientCredentials": return require_sf_cli.clientCredentials({
1154
- loginUrl: read(setting.loginUrlEnv ?? "SF_LOGIN_URL"),
1155
- clientId: read(setting.clientIdEnv ?? "SF_CLIENT_ID"),
1156
- clientSecret: read(setting.clientSecretEnv ?? "SF_CLIENT_SECRET")
1157
- });
1210
+ case "accessToken": {
1211
+ const token = {
1212
+ accessToken: read("accessToken", "SF_ACCESS_TOKEN"),
1213
+ instanceUrl: read("instanceUrl", "SF_INSTANCE_URL")
1214
+ };
1215
+ throwIfMissing(setting.type, problems);
1216
+ return require_sf_cli.accessToken(token);
1217
+ }
1218
+ case "jwtBearer": {
1219
+ const loginUrl = read("loginUrl", "SF_LOGIN_URL");
1220
+ const clientId = read("clientId", "SF_CLIENT_ID");
1221
+ const username = read("username", "SF_USERNAME");
1222
+ const configured = PRIVATE_KEY_SOURCES.filter(([key]) => key in setting);
1223
+ const found = (configured.length > 0 ? configured : PRIVATE_KEY_SOURCES).map(([key, defaultEnv]) => ({
1224
+ key,
1225
+ ...lookup(key, defaultEnv)
1226
+ }));
1227
+ const source = found.find((item) => item.value);
1228
+ if (source === void 0) problems.push(`no private key: ${found.map((item) => item.problem).join(", and ")}`);
1229
+ throwIfMissing(setting.type, problems);
1230
+ const privateKey = source?.key === "privateKeyPath" ? (0, node_fs.readFileSync)(source.value, "utf8") : source?.value ?? "";
1231
+ return require_sf_cli.jwtBearer({
1232
+ loginUrl,
1233
+ clientId,
1234
+ username,
1235
+ privateKey
1236
+ });
1237
+ }
1238
+ case "sfCli": {
1239
+ const targetOrg = "targetOrg" in setting ? read("targetOrg", "") : void 0;
1240
+ throwIfMissing(setting.type, problems);
1241
+ return require_sf_cli.sfCli({ targetOrg });
1242
+ }
1243
+ case "clientCredentials": {
1244
+ const credentials = {
1245
+ loginUrl: read("loginUrl", "SF_LOGIN_URL"),
1246
+ clientId: read("clientId", "SF_CLIENT_ID"),
1247
+ clientSecret: read("clientSecret", "SF_CLIENT_SECRET")
1248
+ };
1249
+ throwIfMissing(setting.type, problems);
1250
+ return require_sf_cli.clientCredentials(credentials);
1251
+ }
1158
1252
  default: throw new Error(`Unknown codegen auth type "${setting.type}".`);
1159
1253
  }
1160
1254
  }
1161
- function jwtBearerFromEnv(setting, env, read) {
1162
- const keyEnv = setting.privateKeyEnv ?? "SF_PRIVATE_KEY";
1163
- const privateKey = env[keyEnv] ? read(keyEnv) : (0, node_fs.readFileSync)(read(setting.privateKeyPathEnv ?? "SF_PRIVATE_KEY_PATH"), "utf8");
1164
- return require_sf_cli.jwtBearer({
1165
- loginUrl: read(setting.loginUrlEnv ?? "SF_LOGIN_URL"),
1166
- clientId: read(setting.clientIdEnv ?? "SF_CLIENT_ID"),
1167
- username: read(setting.usernameEnv ?? "SF_USERNAME"),
1168
- privateKey
1169
- });
1255
+ /**
1256
+ * Loads the sobjectly config and returns an auth provider for its `auth` setting, so the client
1257
+ * logs in the same way as `sobjectly generate`:
1258
+ * `new SalesforceClient({ apiVersion: API_VERSION, auth: await loadAuth() })`.
1259
+ * Throws when no config file is found, or one error listing every missing credential.
1260
+ */
1261
+ async function loadAuth(options = {}) {
1262
+ const cwd = options.cwd ?? process.cwd();
1263
+ let configPath = options.configPath === void 0 ? void 0 : (0, node_path.resolve)(cwd, options.configPath);
1264
+ if (configPath === void 0) {
1265
+ const found = findConfigFiles(cwd);
1266
+ if (found.length > 1) options.warn?.(`found ${found.join(" and ")}; using ${found[0]}. Remove the other one.`);
1267
+ configPath = found[0];
1268
+ }
1269
+ if (configPath === void 0) throw new Error(`No sobjectly config file found in ${cwd} (looked for ${CONFIG_FILE_NAMES.join(", ")}).\nPass { configPath } to loadAuth(), run "npx sobjectly init" to create a config, or pass an auth provider such as clientCredentials() to SalesforceClient directly.`);
1270
+ const { config } = await loadConfig(configPath);
1271
+ return resolveAuth(config.auth, options.env ?? process.env, { warn: options.warn });
1272
+ }
1273
+ function readCredential(setting, key, defaultEnv, env, warn) {
1274
+ const values = setting;
1275
+ if (key in values) {
1276
+ const configured = values[key];
1277
+ const name = typeof configured === "string" ? ENV_PLACEHOLDER.exec(configured)?.[1] : void 0;
1278
+ if (name !== void 0) return fromEnv(env, name, ` (from auth.${key} "${String(configured)}")`);
1279
+ return typeof configured === "string" && configured.length > 0 ? { value: configured } : {
1280
+ value: "",
1281
+ problem: `auth.${key} is empty or undefined (if it reads process.env, that variable is not set)`
1282
+ };
1283
+ }
1284
+ const envKey = `${key}Env`;
1285
+ const legacy = values[envKey];
1286
+ if (typeof legacy === "string") {
1287
+ warn?.(`auth.${envKey} is deprecated and will be removed in 2.0. Use ${key}: process.env.${legacy} in a TypeScript config, or "${key}": "\${${legacy}}" in JSON.`);
1288
+ return fromEnv(env, legacy, "");
1289
+ }
1290
+ return fromEnv(env, defaultEnv, "");
1291
+ }
1292
+ function fromEnv(env, name, origin) {
1293
+ const value = env[name];
1294
+ return value ? { value } : {
1295
+ value: "",
1296
+ problem: `environment variable ${name}${origin} is not set`
1297
+ };
1298
+ }
1299
+ function throwIfMissing(type, problems) {
1300
+ if (problems.length > 0) throw new Error(`Missing Salesforce credentials for auth "${type}":\n${problems.map((problem) => ` - ${problem}`).join("\n")}\nFill them in under auth in the config, or set the environment variables (e.g. with --env-file .env).`);
1170
1301
  }
1171
1302
  async function resolveSObjectNames(client, config, logger) {
1172
1303
  const exclude = new Set((config.exclude ?? []).map((name) => name.toLowerCase()));
@@ -1267,6 +1398,12 @@ Object.defineProperty(exports, "CodegenConfigError", {
1267
1398
  return CodegenConfigError;
1268
1399
  }
1269
1400
  });
1401
+ Object.defineProperty(exports, "DEPRECATED_AUTH_OPTIONS", {
1402
+ enumerable: true,
1403
+ get: function() {
1404
+ return DEPRECATED_AUTH_OPTIONS;
1405
+ }
1406
+ });
1270
1407
  Object.defineProperty(exports, "FIELD_TYPE_MAP", {
1271
1408
  enumerable: true,
1272
1409
  get: function() {
@@ -1315,6 +1452,12 @@ Object.defineProperty(exports, "generateSource", {
1315
1452
  return generateSource;
1316
1453
  }
1317
1454
  });
1455
+ Object.defineProperty(exports, "loadAuth", {
1456
+ enumerable: true,
1457
+ get: function() {
1458
+ return loadAuth;
1459
+ }
1460
+ });
1318
1461
  Object.defineProperty(exports, "loadConfig", {
1319
1462
  enumerable: true,
1320
1463
  get: function() {
@@ -1370,4 +1513,4 @@ Object.defineProperty(exports, "validateConfig", {
1370
1513
  }
1371
1514
  });
1372
1515
 
1373
- //# sourceMappingURL=codegen-Bylrt2Ju.cjs.map
1516
+ //# sourceMappingURL=codegen-Daud-Grz.cjs.map