cf-envsync 0.3.13 → 0.3.15

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.
package/dist/index.js CHANGED
@@ -2286,9 +2286,6 @@ function validateConfig(config) {
2286
2286
  if (!app.path) {
2287
2287
  errors.push(`App "${name}" is missing "path" field`);
2288
2288
  }
2289
- if (!app.workers || Object.keys(app.workers).length === 0) {
2290
- errors.push(`App "${name}" is missing "workers" mapping`);
2291
- }
2292
2289
  if ((!app.secrets || app.secrets.length === 0) && (!app.vars || app.vars.length === 0)) {
2293
2290
  errors.push(`App "${name}" has no "secrets" or "vars" declared`);
2294
2291
  }
@@ -2355,7 +2352,7 @@ function resolveApps(config, appNames) {
2355
2352
  return resolved;
2356
2353
  }
2357
2354
  function getWorkerName(app, environment) {
2358
- return app.workers[environment];
2355
+ return app.workers?.[environment];
2359
2356
  }
2360
2357
  function resolveEnvFilePath(pattern, env2) {
2361
2358
  if (env2 === "local")
@@ -13755,6 +13752,120 @@ ${envIndent}"env": ${inner}
13755
13752
  await writeFile(configPath, content);
13756
13753
  return { success: true, filePath: configPath, updatedCount: Object.keys(vars).length };
13757
13754
  }
13755
+ function findFullKeyRange(text, key, searchStart = 0) {
13756
+ const needle = `"${key}"`;
13757
+ let i2 = searchStart;
13758
+ let inString = false;
13759
+ while (i2 < text.length) {
13760
+ if (inString) {
13761
+ if (text[i2] === "\\" && i2 + 1 < text.length) {
13762
+ i2 += 2;
13763
+ continue;
13764
+ }
13765
+ if (text[i2] === '"')
13766
+ inString = false;
13767
+ i2++;
13768
+ continue;
13769
+ }
13770
+ if (text[i2] === "/" && text[i2 + 1] === "/") {
13771
+ while (i2 < text.length && text[i2] !== `
13772
+ `)
13773
+ i2++;
13774
+ continue;
13775
+ }
13776
+ if (text[i2] === "/" && text[i2 + 1] === "*") {
13777
+ i2 += 2;
13778
+ while (i2 < text.length && !(text[i2] === "*" && text[i2 + 1] === "/"))
13779
+ i2++;
13780
+ i2 += 2;
13781
+ continue;
13782
+ }
13783
+ if (text.startsWith(needle, i2)) {
13784
+ const keyStart = i2;
13785
+ let j = i2 + needle.length;
13786
+ while (j < text.length && (text[j] === " " || text[j] === "\t" || text[j] === `
13787
+ ` || text[j] === "\r"))
13788
+ j++;
13789
+ if (text[j] === ":") {
13790
+ j++;
13791
+ while (j < text.length && (text[j] === " " || text[j] === "\t" || text[j] === `
13792
+ ` || text[j] === "\r"))
13793
+ j++;
13794
+ const end = findValueEnd(text, j);
13795
+ return [keyStart, end];
13796
+ }
13797
+ }
13798
+ if (text[i2] === '"') {
13799
+ inString = true;
13800
+ i2++;
13801
+ continue;
13802
+ }
13803
+ i2++;
13804
+ }
13805
+ return;
13806
+ }
13807
+ function removeJsoncKey(text, key, searchStart, searchEnd) {
13808
+ const range = findFullKeyRange(text, key, searchStart);
13809
+ if (!range || range[0] >= searchEnd)
13810
+ return;
13811
+ const [keyStart, valueEnd] = range;
13812
+ let removeStart = keyStart;
13813
+ let removeEnd = valueEnd;
13814
+ let b2 = keyStart - 1;
13815
+ while (b2 >= 0 && (text[b2] === " " || text[b2] === "\t" || text[b2] === `
13816
+ ` || text[b2] === "\r"))
13817
+ b2--;
13818
+ if (b2 >= 0 && text[b2] === ",") {
13819
+ removeStart = b2;
13820
+ } else {
13821
+ let a2 = valueEnd;
13822
+ while (a2 < text.length && (text[a2] === " " || text[a2] === "\t" || text[a2] === `
13823
+ ` || text[a2] === "\r"))
13824
+ a2++;
13825
+ if (a2 < text.length && text[a2] === ",") {
13826
+ removeEnd = a2 + 1;
13827
+ }
13828
+ let lineStart = keyStart - 1;
13829
+ while (lineStart >= 0 && (text[lineStart] === " " || text[lineStart] === "\t"))
13830
+ lineStart--;
13831
+ if (lineStart >= 0 && text[lineStart] === `
13832
+ `) {
13833
+ removeStart = lineStart;
13834
+ }
13835
+ }
13836
+ return text.slice(0, removeStart) + text.slice(removeEnd);
13837
+ }
13838
+ async function removeWranglerVars(appPath, environments, dryRun = false) {
13839
+ const configPath = findWranglerConfig(appPath);
13840
+ if (!configPath) {
13841
+ return { success: true, removedCount: 0 };
13842
+ }
13843
+ let content = await readFile(configPath);
13844
+ const parsed = JSON.parse(stripJsonc(content));
13845
+ const envSection = parsed?.env ?? {};
13846
+ let removedCount = 0;
13847
+ for (const environment of environments) {
13848
+ if (!envSection[environment]?.vars)
13849
+ continue;
13850
+ removedCount++;
13851
+ if (dryRun)
13852
+ continue;
13853
+ const envRange = findKeyRange(content, "env");
13854
+ if (!envRange)
13855
+ continue;
13856
+ const envObjRange = findKeyRange(content, environment, envRange[0]);
13857
+ if (!envObjRange)
13858
+ continue;
13859
+ const result = removeJsoncKey(content, "vars", envObjRange[0], envObjRange[1]);
13860
+ if (result !== undefined) {
13861
+ content = result;
13862
+ }
13863
+ }
13864
+ if (!dryRun && removedCount > 0) {
13865
+ await writeFile(configPath, content);
13866
+ }
13867
+ return { success: true, filePath: configPath, removedCount };
13868
+ }
13758
13869
  var init_wrangler = __esm(() => {
13759
13870
  init_dist2();
13760
13871
  init_process();
@@ -14410,11 +14521,13 @@ function generateConfigTS(config) {
14410
14521
  for (const [name, app] of Object.entries(config.apps)) {
14411
14522
  lines.push(` ${quoteKey(name)}: {`);
14412
14523
  lines.push(` path: ${JSON.stringify(app.path)},`);
14413
- lines.push(` workers: {`);
14414
- for (const [env2, worker] of Object.entries(app.workers)) {
14415
- lines.push(` ${quoteKey(env2)}: ${JSON.stringify(worker)},`);
14524
+ if (app.workers && Object.keys(app.workers).length > 0) {
14525
+ lines.push(` workers: {`);
14526
+ for (const [env2, worker] of Object.entries(app.workers)) {
14527
+ lines.push(` ${quoteKey(env2)}: ${JSON.stringify(worker)},`);
14528
+ }
14529
+ lines.push(` },`);
14416
14530
  }
14417
- lines.push(` },`);
14418
14531
  if (app.secrets?.length) {
14419
14532
  lines.push(` secrets: ${JSON.stringify(app.secrets)},`);
14420
14533
  }
@@ -15257,6 +15370,89 @@ var init_encrypt = __esm(() => {
15257
15370
  });
15258
15371
  });
15259
15372
 
15373
+ // src/commands/clean.ts
15374
+ var exports_clean = {};
15375
+ __export(exports_clean, {
15376
+ default: () => clean_default
15377
+ });
15378
+ import { join as join9, relative as relative4 } from "node:path";
15379
+ import { unlinkSync } from "node:fs";
15380
+ var clean_default;
15381
+ var init_clean = __esm(() => {
15382
+ init_dist();
15383
+ init_dist2();
15384
+ init_config();
15385
+ init_wrangler();
15386
+ init_fs();
15387
+ clean_default = defineCommand({
15388
+ meta: {
15389
+ name: "clean",
15390
+ description: "Remove generated files (.dev.vars, wrangler.jsonc vars)"
15391
+ },
15392
+ args: {
15393
+ "dry-run": {
15394
+ type: "boolean",
15395
+ description: "Show what would be removed without removing",
15396
+ default: false
15397
+ }
15398
+ },
15399
+ async run({ args }) {
15400
+ const rawConfig = await loadConfig();
15401
+ const errors = validateConfig(rawConfig);
15402
+ if (errors.length > 0) {
15403
+ for (const err of errors)
15404
+ consola.error(err);
15405
+ process.exit(1);
15406
+ }
15407
+ const config = resolveConfig(rawConfig);
15408
+ const apps = Object.values(config.apps);
15409
+ if (apps.length === 0) {
15410
+ consola.warn("No apps to process.");
15411
+ return;
15412
+ }
15413
+ const dryRun = args["dry-run"];
15414
+ let removedFiles = 0;
15415
+ let removedVars = 0;
15416
+ for (const app of apps) {
15417
+ for (const devFileName of app.devFiles) {
15418
+ const filePath = join9(app.absolutePath, devFileName);
15419
+ if (!fileExists(filePath))
15420
+ continue;
15421
+ const rel = relative4(config.projectRoot, filePath);
15422
+ if (dryRun) {
15423
+ consola.log(` Would remove ${rel}`);
15424
+ } else {
15425
+ unlinkSync(filePath);
15426
+ consola.log(` Removed ${rel}`);
15427
+ }
15428
+ removedFiles++;
15429
+ }
15430
+ const result = await removeWranglerVars(app.absolutePath, config.environments, dryRun);
15431
+ if (result.success && result.removedCount > 0) {
15432
+ const rel = relative4(config.projectRoot, result.filePath);
15433
+ if (dryRun) {
15434
+ consola.log(` Would remove ${result.removedCount} vars section(s) from ${rel}`);
15435
+ } else {
15436
+ consola.log(` Removed ${result.removedCount} vars section(s) from ${rel}`);
15437
+ }
15438
+ removedVars += result.removedCount;
15439
+ }
15440
+ }
15441
+ if (removedFiles === 0 && removedVars === 0) {
15442
+ consola.info("Nothing to clean.");
15443
+ return;
15444
+ }
15445
+ const action = dryRun ? "Would remove" : "Removed";
15446
+ const parts = [];
15447
+ if (removedFiles > 0)
15448
+ parts.push(`${removedFiles} file(s)`);
15449
+ if (removedVars > 0)
15450
+ parts.push(`${removedVars} vars section(s)`);
15451
+ consola.success(`${action} ${parts.join(", ")}.`);
15452
+ }
15453
+ });
15454
+ });
15455
+
15260
15456
  // src/index.ts
15261
15457
  init_dist();
15262
15458
  var main = defineCommand({
@@ -15275,7 +15471,8 @@ var main = defineCommand({
15275
15471
  normalize: () => Promise.resolve().then(() => (init_normalize(), exports_normalize)).then((m2) => m2.default),
15276
15472
  merge: () => Promise.resolve().then(() => (init_merge(), exports_merge)).then((m2) => m2.default),
15277
15473
  list: () => Promise.resolve().then(() => (init_list(), exports_list)).then((m2) => m2.default),
15278
- encrypt: () => Promise.resolve().then(() => (init_encrypt(), exports_encrypt)).then((m2) => m2.default)
15474
+ encrypt: () => Promise.resolve().then(() => (init_encrypt(), exports_encrypt)).then((m2) => m2.default),
15475
+ clean: () => Promise.resolve().then(() => (init_clean(), exports_clean)).then((m2) => m2.default)
15279
15476
  }
15280
15477
  });
15281
15478
  runMain(main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-envsync",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Sync .env files to Cloudflare Workers secrets, .dev.vars, and more",
5
5
  "type": "module",
6
6
  "exports": {
@@ -35,8 +35,8 @@ export interface EnvSyncConfig {
35
35
  export interface AppConfig {
36
36
  /** Path to app directory relative to project root */
37
37
  path: string;
38
- /** Cloudflare Worker names per environment */
39
- workers: Record<string, string>;
38
+ /** Cloudflare Worker names per environment (omit for non-worker apps) */
39
+ workers?: Record<string, string>;
40
40
  /** Secret keys for this app (pushed via wrangler secret) */
41
41
  secrets?: string[];
42
42
  /** Var keys for this app (non-secret env vars) */