@varlock/cloudflare-integration 1.0.0 → 1.1.1

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.d.ts CHANGED
@@ -10,6 +10,10 @@ import { PluginConfig } from '@cloudflare/vite-plugin';
10
10
  * `@cloudflare/vite-plugin` (which doesn't support SvelteKit) and uses an
11
11
  * SSR-entry-based env loader.
12
12
  *
13
+ * **Important:** Do not use a `.dev.vars` file alongside this plugin — varlock
14
+ * handles env injection automatically. The plugin will throw an error if a
15
+ * `.dev.vars` file is detected in your project root or build output.
16
+ *
13
17
  * @example
14
18
  * ```ts
15
19
  * import { varlockCloudflareVitePlugin } from '@varlock/cloudflare-integration';
package/dist/index.js CHANGED
@@ -1,13 +1,15 @@
1
- import path from 'path';
1
+ import path2 from 'path';
2
+ import { existsSync, readdirSync, writeFileSync, unlinkSync } from 'fs';
3
+ import { execSync, spawn } from 'child_process';
2
4
  import { initVarlockEnv } from 'varlock/env';
3
5
  import { patchGlobalConsole } from 'varlock/patch-console';
4
6
  import { patchGlobalServerResponse } from 'varlock/patch-server-response';
5
7
  import { patchGlobalResponse } from 'varlock/patch-response';
6
8
  import { createDebug } from 'varlock';
7
- import { execSyncVarlock } from 'varlock/exec-sync-varlock';
9
+ import { execSyncVarlock, VarlockExecError } from 'varlock/exec-sync-varlock';
8
10
  import { cloudflare } from '@cloudflare/vite-plugin';
9
11
 
10
- // ../vite/dist/index.js
12
+ // src/index.ts
11
13
  var __create = Object.create;
12
14
  var __defProp = Object.defineProperty;
13
15
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -34,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
36
  mod
35
37
  ));
36
38
  var require_ast_matcher = __commonJS({
37
- "../../../node_modules/.bun/ast-matcher@1.2.0/node_modules/ast-matcher/index.js"(exports$1, module) {
39
+ "../../../node_modules/.bun/ast-matcher@1.2.0/node_modules/ast-matcher/index.js"(exports, module) {
38
40
  var STOP = false;
39
41
  var SKIP_BRANCH = 1;
40
42
  var IGNORED_KEYS = ["start", "end", "loc", "location", "locations", "line", "column", "range", "ranges", "raw", "extra"];
@@ -1410,23 +1412,24 @@ var loadCount = 0;
1410
1412
  function reloadConfig(cwd) {
1411
1413
  debug("loading config - count =", ++loadCount, cwd ? `(cwd: ${cwd})` : "");
1412
1414
  try {
1413
- const execResult = execSyncVarlock("load --format json-full --compact", {
1415
+ const { stdout } = execSyncVarlock("load --format json-full --compact", {
1416
+ fullResult: true,
1414
1417
  env: originalProcessEnv,
1415
1418
  ...cwd && { cwd }
1416
1419
  });
1417
- process.env.__VARLOCK_ENV = execResult;
1418
- varlockLoadedEnv = JSON.parse(process.env.__VARLOCK_ENV);
1420
+ process.env.__VARLOCK_ENV = stdout;
1421
+ varlockLoadedEnv = JSON.parse(stdout);
1419
1422
  configIsValid = true;
1420
1423
  } catch (err) {
1421
- const errAny = err;
1422
- const stdout = errAny?.stdout?.toString();
1423
- if (stdout) {
1424
- try {
1425
- varlockLoadedEnv = JSON.parse(stdout);
1426
- } catch {
1424
+ if (err instanceof VarlockExecError) {
1425
+ if (err.stdout) {
1426
+ try {
1427
+ varlockLoadedEnv = JSON.parse(err.stdout);
1428
+ } catch {
1429
+ }
1427
1430
  }
1431
+ if (err.stderr) console.error(err.stderr);
1428
1432
  }
1429
- if (errAny?.stderr) console.error(errAny.stderr.toString());
1430
1433
  configIsValid = false;
1431
1434
  resetStaticReplacements();
1432
1435
  return;
@@ -1438,10 +1441,46 @@ function reloadConfig(cwd) {
1438
1441
  resetStaticReplacements();
1439
1442
  }
1440
1443
  reloadConfig();
1444
+ var VARLOCK_INIT_MODULE_ID = "\0varlock-ssr-init";
1441
1445
  function varlockVitePlugin(vitePluginOptions) {
1446
+ function buildInitModuleCode() {
1447
+ const ssrInjectMode = vitePluginOptions?.ssrInjectMode ?? "init-only";
1448
+ const lines = [
1449
+ "// Virtual module generated by @varlock/vite-integration",
1450
+ "// Runs before any user code to ensure ENV is available at module top-level",
1451
+ "globalThis.__varlockThrowOnMissingKeys = true;"
1452
+ ];
1453
+ if (ssrInjectMode === "auto-load") {
1454
+ lines.push("import 'varlock/auto-load';");
1455
+ } else {
1456
+ if (ssrInjectMode === "resolved-env") {
1457
+ lines.push(`globalThis.__varlockLoadedEnv = ${JSON.stringify(varlockLoadedEnv)};`);
1458
+ }
1459
+ if (vitePluginOptions?.ssrEntryCode?.length) {
1460
+ lines.push(...vitePluginOptions.ssrEntryCode);
1461
+ }
1462
+ lines.push(
1463
+ "import { initVarlockEnv } from 'varlock/env';",
1464
+ "import { patchGlobalConsole } from 'varlock/patch-console';",
1465
+ "import { patchGlobalResponse } from 'varlock/patch-response';"
1466
+ );
1467
+ lines.push(
1468
+ "initVarlockEnv();",
1469
+ "patchGlobalConsole();"
1470
+ );
1471
+ lines.push("patchGlobalResponse();");
1472
+ }
1473
+ return lines.join("\n");
1474
+ }
1442
1475
  return {
1443
1476
  name: "inject-varlock-config",
1444
1477
  enforce: "post",
1478
+ resolveId(id) {
1479
+ if (id === VARLOCK_INIT_MODULE_ID) return id;
1480
+ },
1481
+ load(id) {
1482
+ if (id === VARLOCK_INIT_MODULE_ID) return buildInitModuleCode();
1483
+ },
1445
1484
  // hook to modify config before it is resolved
1446
1485
  async config(config, env) {
1447
1486
  debug("vite plugin - config fn called");
@@ -1460,8 +1499,8 @@ See https://varlock.dev/integrations/vite/ for more details.
1460
1499
  `);
1461
1500
  }
1462
1501
  isDevCommand = env.command === "serve";
1463
- const projectRoot = config.root ? path.resolve(config.root) : void 0;
1464
- const rootDiffersFromCwd = !!(projectRoot && path.relative(projectRoot, process.cwd()) !== "");
1502
+ const projectRoot = config.root ? path2.resolve(config.root) : void 0;
1503
+ const rootDiffersFromCwd = !!(projectRoot && path2.relative(projectRoot, process.cwd()) !== "");
1465
1504
  if (rootDiffersFromCwd) {
1466
1505
  reloadConfig(projectRoot);
1467
1506
  } else if (isFirstLoad) {
@@ -1495,7 +1534,7 @@ See https://varlock.dev/integrations/vite/ for more details.
1495
1534
  for (const varlockSource of varlockLoadedEnv.sources) {
1496
1535
  if (!varlockSource.enabled) continue;
1497
1536
  if (varlockLoadedEnv.basePath && varlockSource.path) {
1498
- config.configFileDependencies.push(path.resolve(varlockLoadedEnv.basePath, varlockSource.path));
1537
+ config.configFileDependencies.push(path2.resolve(varlockLoadedEnv.basePath, varlockSource.path));
1499
1538
  }
1500
1539
  }
1501
1540
  },
@@ -1521,51 +1560,27 @@ See https://varlock.dev/integrations/vite/ for more details.
1521
1560
  const fileExt = id.split("?")[0].split("#")[0].split(".").pop() || "";
1522
1561
  let isEntry = false;
1523
1562
  if (SUPPORTED_FILES.includes(fileExt)) {
1524
- const moduleIds = Array.from(this.getModuleIds());
1525
- if (moduleIds[0] === id) isEntry = true;
1563
+ try {
1564
+ const moduleInfo = this.getModuleInfo(id);
1565
+ if (moduleInfo?.isEntry) isEntry = true;
1566
+ } catch {
1567
+ }
1568
+ if (!isEntry) {
1569
+ const moduleIds = Array.from(this.getModuleIds());
1570
+ if (moduleIds[0] === id) isEntry = true;
1571
+ }
1526
1572
  }
1527
1573
  if (vitePluginOptions?.ssrEntryModuleIds?.includes(id)) isEntry = true;
1528
1574
  if (isEntry) {
1529
1575
  debug(`detected entry: ${id}`);
1530
- let isDevEnv = false;
1531
- if (this.environment) {
1532
- isDevEnv = this.environment.mode === "dev";
1533
- } else {
1534
- isDevEnv = isDevCommand;
1535
- }
1536
- const injectCode = [
1537
- "// INJECTED BY @varlock/vite-integration ----",
1538
- "globalThis.__varlockThrowOnMissingKeys = true;"
1539
- ];
1576
+ const injectCode = ["// INJECTED BY @varlock/vite-integration ----"];
1540
1577
  if (options?.ssr) {
1541
- const ssrInjectMode = vitePluginOptions?.ssrInjectMode ?? "init-only";
1542
- debug("ssrInjectMode =", ssrInjectMode, "isDev =", isDevEnv);
1543
- if (ssrInjectMode === "auto-load") {
1544
- injectCode.push(
1545
- "import 'varlock/auto-load';"
1546
- );
1547
- } else {
1548
- if (ssrInjectMode === "resolved-env") {
1549
- injectCode.push(`globalThis.__varlockLoadedEnv = ${JSON.stringify(varlockLoadedEnv)};`);
1550
- }
1551
- if (vitePluginOptions?.ssrEntryCode?.length) {
1552
- injectCode.push(...vitePluginOptions.ssrEntryCode);
1553
- }
1554
- injectCode.push(
1555
- "import { initVarlockEnv } from 'varlock/env';",
1556
- "import { patchGlobalConsole } from 'varlock/patch-console';",
1557
- "import { patchGlobalResponse } from 'varlock/patch-response';"
1558
- );
1559
- injectCode.push(
1560
- "initVarlockEnv();",
1561
- "patchGlobalConsole();"
1562
- );
1563
- injectCode.push("patchGlobalResponse();");
1564
- }
1578
+ injectCode.push(`import '${VARLOCK_INIT_MODULE_ID}';`);
1565
1579
  } else {
1580
+ injectCode.push("globalThis.__varlockThrowOnMissingKeys = true;");
1581
+ const isDevEnv = this.environment ? this.environment.mode === "dev" : isDevCommand;
1566
1582
  if (isDevEnv) {
1567
1583
  injectCode.push(
1568
- "// NOTE - __varlockValidKeys is only injected during development",
1569
1584
  `globalThis.__varlockValidKeys = ${JSON.stringify(Object.keys(varlockLoadedEnv?.config || {}))};`
1570
1585
  );
1571
1586
  }
@@ -1655,7 +1670,101 @@ if (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Work
1655
1670
  `;
1656
1671
 
1657
1672
  // src/index.ts
1673
+ var isWindows = process.platform === "win32";
1658
1674
  var CLOUDFLARE_PLUGIN_NAME = "vite-plugin-cloudflare";
1675
+ var CF_SECRET_MAX_BYTES = 5120;
1676
+ function findDevVarsPath(root) {
1677
+ const distDir = path2.resolve(root, "dist");
1678
+ if (!existsSync(distDir)) return void 0;
1679
+ for (const entry of readdirSync(distDir, { withFileTypes: true })) {
1680
+ if (!entry.isDirectory()) continue;
1681
+ const wranglerPath = path2.join(distDir, entry.name, "wrangler.json");
1682
+ if (existsSync(wranglerPath)) {
1683
+ return path2.join(distDir, entry.name, ".dev.vars");
1684
+ }
1685
+ }
1686
+ return void 0;
1687
+ }
1688
+ function cleanupFile(filePath) {
1689
+ try {
1690
+ unlinkSync(filePath);
1691
+ } catch {
1692
+ }
1693
+ }
1694
+ function chunkString(str, maxBytes) {
1695
+ const chunks = [];
1696
+ let current = "";
1697
+ let currentBytes = 0;
1698
+ for (const char of str) {
1699
+ const charBytes = Buffer.byteLength(char);
1700
+ if (currentBytes + charBytes > maxBytes && current) {
1701
+ chunks.push(current);
1702
+ current = "";
1703
+ currentBytes = 0;
1704
+ }
1705
+ current += char;
1706
+ currentBytes += charBytes;
1707
+ }
1708
+ if (current) chunks.push(current);
1709
+ return chunks;
1710
+ }
1711
+ function formatEnvLine(key, value) {
1712
+ if (!value.includes("'")) {
1713
+ return `${key}='${value}'`;
1714
+ }
1715
+ const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
1716
+ return `${key}="${escaped}"`;
1717
+ }
1718
+ function formatDevVarsContent(graph, serializedGraph) {
1719
+ const lines = [];
1720
+ for (const key in graph.config) {
1721
+ const item = graph.config[key];
1722
+ if (item.value === void 0) continue;
1723
+ const strValue = typeof item.value === "string" ? item.value : JSON.stringify(item.value);
1724
+ lines.push(formatEnvLine(key, strValue));
1725
+ }
1726
+ if (Buffer.byteLength(serializedGraph) <= CF_SECRET_MAX_BYTES) {
1727
+ lines.push(formatEnvLine("__VARLOCK_ENV", serializedGraph));
1728
+ } else {
1729
+ const chunks = chunkString(serializedGraph, CF_SECRET_MAX_BYTES);
1730
+ lines.push(formatEnvLine("__VARLOCK_ENV_CHUNKS", String(chunks.length)));
1731
+ for (let i = 0; i < chunks.length; i++) {
1732
+ lines.push(formatEnvLine(`__VARLOCK_ENV_${i}`, chunks[i]));
1733
+ }
1734
+ }
1735
+ return lines.join("\n");
1736
+ }
1737
+ function serveFifoOrFile(filePath, content) {
1738
+ let fifoProcess;
1739
+ if (isWindows) {
1740
+ writeFileSync(filePath, content);
1741
+ } else {
1742
+ execSync(`mkfifo -m 0600 "${filePath}"`);
1743
+ const encoded = Buffer.from(content).toString("base64");
1744
+ const parentPid = process.pid;
1745
+ fifoProcess = spawn(process.execPath, [
1746
+ "-e",
1747
+ `
1748
+ const fs = require('fs');
1749
+ const content = Buffer.from('${encoded}', 'base64').toString();
1750
+ // Exit if the parent process dies (orphan protection).
1751
+ setInterval(() => {
1752
+ try { process.kill(${parentPid}, 0); }
1753
+ catch { process.exit(); }
1754
+ }, 2000);
1755
+ (function serve() {
1756
+ try { fs.writeFileSync(${JSON.stringify(filePath)}, content); setImmediate(serve); }
1757
+ catch { process.exit(); }
1758
+ })();
1759
+ `
1760
+ ], { stdio: ["ignore", "ignore", "ignore"] });
1761
+ }
1762
+ return {
1763
+ stop() {
1764
+ fifoProcess?.kill();
1765
+ }
1766
+ };
1767
+ }
1659
1768
  function varlockCloudflareVitePlugin(cloudflareOptions) {
1660
1769
  const conflictGuard = {
1661
1770
  name: "varlock-cloudflare-conflict-guard",
@@ -1674,8 +1783,15 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1674
1783
  const modeDetector = {
1675
1784
  name: "varlock-cloudflare-mode",
1676
1785
  enforce: "pre",
1677
- config(_config, env) {
1786
+ config(config, env) {
1678
1787
  isDevMode = env.command === "serve";
1788
+ const root = config.root ? path2.resolve(config.root) : process.cwd();
1789
+ const devVarsPath = path2.resolve(root, ".dev.vars");
1790
+ if (existsSync(devVarsPath)) {
1791
+ throw new Error(
1792
+ "[varlock] A .dev.vars file was found in your project root, which conflicts with varlock's env management.\nRemove the .dev.vars file \u2014 varlock handles env injection automatically."
1793
+ );
1794
+ }
1679
1795
  }
1680
1796
  };
1681
1797
  const userConfig = cloudflareOptions?.config;
@@ -1687,7 +1803,7 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1687
1803
  userResult = userConfig;
1688
1804
  }
1689
1805
  if (!isDevMode) return userResult;
1690
- const serializedGraph = execSyncVarlock("load --format json-full --compact");
1806
+ const { stdout: serializedGraph } = execSyncVarlock("load --format json-full --compact", { fullResult: true });
1691
1807
  let graph;
1692
1808
  try {
1693
1809
  graph = JSON.parse(serializedGraph);
@@ -1718,9 +1834,44 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1718
1834
  ...cloudflareOptions,
1719
1835
  config: mergedConfig
1720
1836
  });
1837
+ let resolvedRoot = "";
1838
+ const previewEnvInjector = {
1839
+ name: "varlock-cloudflare-preview-env",
1840
+ configResolved(config) {
1841
+ resolvedRoot = config.root;
1842
+ },
1843
+ configurePreviewServer(server) {
1844
+ if (!resolvedRoot) return;
1845
+ const devVarsPath = findDevVarsPath(resolvedRoot);
1846
+ if (!devVarsPath) return;
1847
+ if (existsSync(devVarsPath)) {
1848
+ throw new Error(
1849
+ "[varlock] A .dev.vars file was found in the build output, which conflicts with varlock's env management.\nRemove your project-root .dev.vars file \u2014 varlock handles env injection automatically."
1850
+ );
1851
+ }
1852
+ const serializedGraph = process.env.__VARLOCK_ENV;
1853
+ if (!serializedGraph || !varlockLoadedEnv) return;
1854
+ const content = formatDevVarsContent(varlockLoadedEnv, serializedGraph);
1855
+ const fifo = serveFifoOrFile(devVarsPath, content);
1856
+ const origClose = server.close.bind(server);
1857
+ server.close = async () => {
1858
+ fifo.stop();
1859
+ cleanupFile(devVarsPath);
1860
+ return origClose();
1861
+ };
1862
+ const onExit = () => {
1863
+ fifo.stop();
1864
+ cleanupFile(devVarsPath);
1865
+ };
1866
+ process.on("exit", onExit);
1867
+ process.on("SIGINT", onExit);
1868
+ process.on("SIGTERM", onExit);
1869
+ }
1870
+ };
1721
1871
  return [
1722
1872
  conflictGuard,
1723
1873
  modeDetector,
1874
+ previewEnvInjector,
1724
1875
  varlockPlugin,
1725
1876
  // cloudflare() may return a single plugin or an array
1726
1877
  ...Array.isArray(cloudflarePlugin) ? cloudflarePlugin : [cloudflarePlugin]