cf-envsync 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +138 -38
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13268,7 +13268,7 @@ var init_env_file = __esm(() => {
13268
13268
  });
13269
13269
 
13270
13270
  // src/core/resolver.ts
13271
- import { normalize, relative } from "node:path";
13271
+ import { join as join4, normalize, relative } from "node:path";
13272
13272
  async function resolveAppEnv(config, app, environment) {
13273
13273
  const layers = [];
13274
13274
  const encryption = config.raw.encryption;
@@ -13281,8 +13281,8 @@ async function resolveAppEnv(config, app, environment) {
13281
13281
  if (Object.keys(rootEnv).length > 0) {
13282
13282
  layers.push({ source: rootEnvPath, map: rootEnv });
13283
13283
  }
13284
- if (config.raw.envFiles.perApp && environment !== "local") {
13285
- const appEnvPath = getAppEnvPath(config, app, environment);
13284
+ if (config.raw.envFiles.perApp) {
13285
+ const appEnvPath = environment === "local" ? join4(app.absolutePath, config.raw.envFiles.local) : getAppEnvPath(config, app, environment);
13286
13286
  if (normalize(appEnvPath) !== normalize(rootEnvPath)) {
13287
13287
  const appEnv = await loadEnvFile(appEnvPath, environment, config.projectRoot, encryption);
13288
13288
  if (Object.keys(appEnv).length > 0) {
@@ -13332,7 +13332,7 @@ var exports_dev = {};
13332
13332
  __export(exports_dev, {
13333
13333
  default: () => dev_default
13334
13334
  });
13335
- import { join as join4, relative as relative2 } from "node:path";
13335
+ import { join as join5, relative as relative2 } from "node:path";
13336
13336
  function parseAppNames(args) {
13337
13337
  const rest = args._;
13338
13338
  return rest?.length ? rest : undefined;
@@ -13399,7 +13399,7 @@ var init_dev = __esm(() => {
13399
13399
  continue;
13400
13400
  }
13401
13401
  for (const devFileName of app.devFiles) {
13402
- const devFilePath = join4(app.absolutePath, devFileName);
13402
+ const devFilePath = join5(app.absolutePath, devFileName);
13403
13403
  const relDevFile = relative2(config.projectRoot, devFilePath);
13404
13404
  if (args["dry-run"]) {
13405
13405
  consola.log(`
@@ -13485,6 +13485,48 @@ async function exec(command, options = {}) {
13485
13485
  var init_process = () => {};
13486
13486
 
13487
13487
  // src/core/wrangler.ts
13488
+ import { join as join6 } from "node:path";
13489
+ function stripJsonc(text) {
13490
+ let result = "";
13491
+ let i2 = 0;
13492
+ let inString = false;
13493
+ while (i2 < text.length) {
13494
+ if (inString) {
13495
+ result += text[i2];
13496
+ if (text[i2] === "\\" && i2 + 1 < text.length) {
13497
+ result += text[i2 + 1];
13498
+ i2 += 2;
13499
+ continue;
13500
+ }
13501
+ if (text[i2] === '"')
13502
+ inString = false;
13503
+ i2++;
13504
+ continue;
13505
+ }
13506
+ if (text[i2] === '"') {
13507
+ inString = true;
13508
+ result += text[i2];
13509
+ i2++;
13510
+ continue;
13511
+ }
13512
+ if (text[i2] === "/" && text[i2 + 1] === "/") {
13513
+ while (i2 < text.length && text[i2] !== `
13514
+ `)
13515
+ i2++;
13516
+ continue;
13517
+ }
13518
+ if (text[i2] === "/" && text[i2 + 1] === "*") {
13519
+ i2 += 2;
13520
+ while (i2 < text.length && !(text[i2] === "*" && text[i2 + 1] === "/"))
13521
+ i2++;
13522
+ i2 += 2;
13523
+ continue;
13524
+ }
13525
+ result += text[i2];
13526
+ i2++;
13527
+ }
13528
+ return result.replace(/,(\s*[}\]])/g, "$1");
13529
+ }
13488
13530
  async function checkWrangler() {
13489
13531
  const result = await exec(["npx", "wrangler", "--version"]);
13490
13532
  return result.success;
@@ -13531,9 +13573,31 @@ async function listSecrets(workerName, _environment, cwd) {
13531
13573
  `).map((line) => line.trim()).filter((line) => line.length > 0);
13532
13574
  }
13533
13575
  }
13576
+ function findWranglerConfig(appPath) {
13577
+ for (const name of ["wrangler.jsonc", "wrangler.json"]) {
13578
+ const p = join6(appPath, name);
13579
+ if (fileExists(p))
13580
+ return p;
13581
+ }
13582
+ return;
13583
+ }
13584
+ async function updateWranglerVars(appPath, vars) {
13585
+ const configPath = findWranglerConfig(appPath);
13586
+ if (!configPath) {
13587
+ return { success: false, updatedCount: 0 };
13588
+ }
13589
+ const content = await readFile(configPath);
13590
+ const stripped = stripJsonc(content);
13591
+ const config = JSON.parse(stripped);
13592
+ config.vars = { ...config.vars || {}, ...vars };
13593
+ await writeFile(configPath, JSON.stringify(config, null, 2) + `
13594
+ `);
13595
+ return { success: true, filePath: configPath, updatedCount: Object.keys(vars).length };
13596
+ }
13534
13597
  var init_wrangler = __esm(() => {
13535
13598
  init_dist2();
13536
13599
  init_process();
13600
+ init_fs();
13537
13601
  });
13538
13602
 
13539
13603
  // src/commands/push.ts
@@ -13555,7 +13619,7 @@ var init_push = __esm(() => {
13555
13619
  push_default = defineCommand({
13556
13620
  meta: {
13557
13621
  name: "push",
13558
- description: "Push env vars to Cloudflare Workers secrets"
13622
+ description: "Push secrets (wrangler) and vars (wrangler.jsonc) to Cloudflare Workers"
13559
13623
  },
13560
13624
  args: {
13561
13625
  env: {
@@ -13636,52 +13700,88 @@ var init_push = __esm(() => {
13636
13700
  consola.warn(`${progress}No worker defined for ${app.name} in ${environment}. Skipping.`);
13637
13701
  continue;
13638
13702
  }
13639
- consola.start(`${progress}Pushing secrets for ${app.name} → ${workerName} (${environment})...`);
13703
+ consola.start(`${progress}Pushing ${app.name} → ${workerName} (${environment})...`);
13640
13704
  const resolved = await resolveAppEnv(config, app, environment);
13641
13705
  let secretsToPush;
13706
+ let varsToPush;
13707
+ const secretKeySet = new Set(app.secrets ?? []);
13708
+ const varsKeySet = new Set(app.vars ?? []);
13642
13709
  if (args.shared) {
13643
13710
  secretsToPush = {};
13711
+ varsToPush = {};
13644
13712
  for (const [key, value] of Object.entries(resolved.map)) {
13645
13713
  if (sharedKeys.has(key)) {
13646
- secretsToPush[key] = value;
13714
+ if (secretKeySet.has(key)) {
13715
+ secretsToPush[key] = value;
13716
+ } else if (varsKeySet.has(key)) {
13717
+ varsToPush[key] = value;
13718
+ }
13647
13719
  }
13648
13720
  }
13649
13721
  } else {
13650
- const secretKeySet = new Set(app.secrets ?? []);
13651
13722
  secretsToPush = {};
13723
+ varsToPush = {};
13652
13724
  for (const [key, value] of Object.entries(resolved.map)) {
13653
13725
  if (secretKeySet.has(key)) {
13654
13726
  secretsToPush[key] = value;
13727
+ } else if (varsKeySet.has(key)) {
13728
+ varsToPush[key] = value;
13655
13729
  }
13656
13730
  }
13657
13731
  }
13658
- const keyCount = Object.keys(secretsToPush).length;
13659
- if (keyCount === 0) {
13732
+ const secretCount = Object.keys(secretsToPush).length;
13733
+ const varsCount = Object.keys(varsToPush).length;
13734
+ if (secretCount === 0 && varsCount === 0) {
13660
13735
  const reason = args.shared ? " (no shared keys for this app)" : "";
13661
- consola.warn(` No secrets to push for ${app.name}${reason}. Skipping.`);
13736
+ consola.warn(` Nothing to push for ${app.name}${reason}. Skipping.`);
13662
13737
  continue;
13663
13738
  }
13664
13739
  if (args["dry-run"]) {
13665
- consola.info(` Would push ${keyCount} secrets to worker "${workerName}"`);
13666
- for (const key of Object.keys(secretsToPush)) {
13667
- const isShared = sharedKeys.has(key) ? " (shared)" : "";
13668
- consola.log(` ${key}${isShared}`);
13740
+ if (secretCount > 0) {
13741
+ consola.info(` Would push ${secretCount} secrets to worker "${workerName}"`);
13742
+ for (const key of Object.keys(secretsToPush)) {
13743
+ const isShared = sharedKeys.has(key) ? " (shared)" : "";
13744
+ consola.log(` ${key}${isShared}`);
13745
+ }
13746
+ }
13747
+ if (varsCount > 0) {
13748
+ consola.info(` Would write ${varsCount} vars to wrangler config`);
13749
+ for (const key of Object.keys(varsToPush)) {
13750
+ const isShared = sharedKeys.has(key) ? " (shared)" : "";
13751
+ consola.log(` ${key}${isShared}`);
13752
+ }
13669
13753
  }
13670
13754
  continue;
13671
13755
  }
13672
13756
  if (!args.force) {
13673
- const confirmed = await consola.prompt(` Push ${keyCount} secrets to worker "${workerName}" (${environment})?`, { type: "confirm" });
13757
+ const parts = [];
13758
+ if (secretCount > 0)
13759
+ parts.push(`${secretCount} secrets`);
13760
+ if (varsCount > 0)
13761
+ parts.push(`${varsCount} vars`);
13762
+ const confirmed = await consola.prompt(` Push ${parts.join(" + ")} to "${workerName}" (${environment})?`, { type: "confirm" });
13674
13763
  if (!confirmed) {
13675
13764
  consola.info(` Skipped ${app.name}.`);
13676
13765
  continue;
13677
13766
  }
13678
13767
  }
13679
- const result = await pushSecrets(workerName, secretsToPush, environment, app.absolutePath);
13680
- if (result.success) {
13681
- consola.success(` Pushed ${keyCount} secrets to ${workerName}`);
13682
- } else {
13683
- consola.error(` Failed to push secrets to ${workerName}`);
13684
- hasFailure = true;
13768
+ if (secretCount > 0) {
13769
+ const result = await pushSecrets(workerName, secretsToPush, environment, app.absolutePath);
13770
+ if (result.success) {
13771
+ consola.success(` Pushed ${secretCount} secrets to ${workerName}`);
13772
+ } else {
13773
+ consola.error(` Failed to push secrets to ${workerName}`);
13774
+ hasFailure = true;
13775
+ }
13776
+ }
13777
+ if (varsCount > 0) {
13778
+ const varsResult = await updateWranglerVars(app.absolutePath, varsToPush);
13779
+ if (varsResult.success) {
13780
+ consola.success(` Wrote ${varsCount} vars to ${varsResult.filePath}`);
13781
+ } else {
13782
+ consola.error(` No wrangler.jsonc found in ${app.absolutePath}. Cannot write vars.`);
13783
+ hasFailure = true;
13784
+ }
13685
13785
  }
13686
13786
  }
13687
13787
  if (hasFailure) {
@@ -13785,7 +13885,7 @@ var exports_validate = {};
13785
13885
  __export(exports_validate, {
13786
13886
  default: () => validate_default
13787
13887
  });
13788
- import { join as join5 } from "node:path";
13888
+ import { join as join7 } from "node:path";
13789
13889
  function parseAppNames4(args, skip = 1) {
13790
13890
  const rest = args._?.slice(skip);
13791
13891
  return rest?.length ? rest : undefined;
@@ -13840,7 +13940,7 @@ var init_validate = __esm(() => {
13840
13940
  appNames = undefined;
13841
13941
  }
13842
13942
  const apps = resolveApps(config, appNames);
13843
- const examplePath = join5(config.projectRoot, ".env.example");
13943
+ const examplePath = join7(config.projectRoot, ".env.example");
13844
13944
  if (!fileExists(examplePath)) {
13845
13945
  consola.error("No .env.example found at project root.");
13846
13946
  process.exit(1);
@@ -14128,7 +14228,7 @@ var exports_init = {};
14128
14228
  __export(exports_init, {
14129
14229
  default: () => init_default
14130
14230
  });
14131
- import { join as join6, relative as relative3, basename } from "node:path";
14231
+ import { join as join8, relative as relative3, basename } from "node:path";
14132
14232
  function generateConfigTS(config) {
14133
14233
  const lines = [
14134
14234
  `import { defineConfig } from "cf-envsync";`,
@@ -14209,10 +14309,10 @@ var init_init = __esm(() => {
14209
14309
  },
14210
14310
  async run({ args }) {
14211
14311
  const cwd = process.cwd();
14212
- const existingConfig = CONFIG_FILES.find((f3) => fileExists(join6(cwd, f3)));
14312
+ const existingConfig = CONFIG_FILES.find((f3) => fileExists(join8(cwd, f3)));
14213
14313
  if (existingConfig) {
14214
14314
  consola.warn(`${existingConfig} already exists.`);
14215
- const existingContent = await readFile(join6(cwd, existingConfig));
14315
+ const existingContent = await readFile(join8(cwd, existingConfig));
14216
14316
  const lines = existingContent.split(`
14217
14317
  `);
14218
14318
  const preview = lines.length > 20 ? [...lines.slice(0, 20), ` ... (${lines.length - 20} more lines)`].join(`
@@ -14252,8 +14352,8 @@ ${preview}
14252
14352
  ` + " Falling back to manual configuration.");
14253
14353
  }
14254
14354
  for (const wranglerFile of wranglerFiles.sort()) {
14255
- const fullPath = join6(cwd, wranglerFile);
14256
- const appDir = join6(cwd, wranglerFile, "..");
14355
+ const fullPath = join8(cwd, wranglerFile);
14356
+ const appDir = join8(cwd, wranglerFile, "..");
14257
14357
  const appPath = relative3(cwd, appDir);
14258
14358
  const appName = basename(appDir);
14259
14359
  consola.info(` Found ${wranglerFile}`);
@@ -14354,10 +14454,10 @@ ${preview}
14354
14454
  apps,
14355
14455
  ...shared.length > 0 ? { shared } : {}
14356
14456
  };
14357
- const configPath = join6(cwd, "envsync.config.ts");
14457
+ const configPath = join8(cwd, "envsync.config.ts");
14358
14458
  const tsContent = generateConfigTS(config);
14359
14459
  if (existingConfig && existingConfig !== "envsync.config.ts") {
14360
- const oldPath = join6(cwd, existingConfig);
14460
+ const oldPath = join8(cwd, existingConfig);
14361
14461
  if (fileExists(oldPath)) {
14362
14462
  const { unlink } = await import("node:fs/promises");
14363
14463
  await unlink(oldPath);
@@ -14365,7 +14465,7 @@ ${preview}
14365
14465
  }
14366
14466
  await writeFile(configPath, tsContent);
14367
14467
  consola.success("Created envsync.config.ts");
14368
- const examplePath = join6(cwd, ".env.example");
14468
+ const examplePath = join8(cwd, ".env.example");
14369
14469
  if (!fileExists(examplePath)) {
14370
14470
  const allKeys = new Set;
14371
14471
  for (const app of Object.values(apps)) {
@@ -14388,20 +14488,20 @@ ${preview}
14388
14488
  for (const env2 of environments) {
14389
14489
  if (env2 === "local")
14390
14490
  continue;
14391
- const envFile = join6(cwd, `.env.${env2}`);
14491
+ const envFile = join8(cwd, `.env.${env2}`);
14392
14492
  if (!fileExists(envFile)) {
14393
14493
  await writeFile(envFile, `# ${env2} environment variables
14394
14494
  `);
14395
14495
  consola.success(`Created .env.${env2}`);
14396
14496
  }
14397
14497
  }
14398
- const rootEnv = join6(cwd, ".env");
14498
+ const rootEnv = join8(cwd, ".env");
14399
14499
  if (!fileExists(rootEnv)) {
14400
14500
  await writeFile(rootEnv, `# Local environment variables
14401
14501
  `);
14402
14502
  consola.success("Created .env");
14403
14503
  }
14404
- const gitignorePath = join6(cwd, ".gitignore");
14504
+ const gitignorePath = join8(cwd, ".gitignore");
14405
14505
  const gitignoreEntries = [".env.local", ".env.keys", ".env.password", "**/.dev.vars"];
14406
14506
  if (fileExists(gitignorePath)) {
14407
14507
  const existing = await readFile(gitignorePath);
@@ -14422,7 +14522,7 @@ ${preview}
14422
14522
  `);
14423
14523
  consola.success(`Created .gitignore`);
14424
14524
  }
14425
- const gitattrsPath = join6(cwd, ".gitattributes");
14525
+ const gitattrsPath = join8(cwd, ".gitattributes");
14426
14526
  const mergeDriverLines = `.env merge=envsync
14427
14527
  .env.* merge=envsync
14428
14528
  `;
@@ -14438,7 +14538,7 @@ ${preview}
14438
14538
  await writeFile(gitattrsPath, mergeDriverLines);
14439
14539
  consola.success("Created .gitattributes with merge driver");
14440
14540
  }
14441
- const gitConfigPath = join6(cwd, ".git", "config");
14541
+ const gitConfigPath = join8(cwd, ".git", "config");
14442
14542
  if (fileExists(gitConfigPath)) {
14443
14543
  const gitConfig = await readFile(gitConfigPath);
14444
14544
  if (!gitConfig.includes('[merge "envsync"]')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-envsync",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "Sync .env files to Cloudflare Workers secrets, .dev.vars, and more",
5
5
  "type": "module",
6
6
  "exports": {