@varlock/cloudflare-integration 1.1.2 → 1.1.3

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
@@ -1384,14 +1384,105 @@ function createReplacerTransformFn(opts) {
1384
1384
  return magicString;
1385
1385
  };
1386
1386
  }
1387
+ var ANSI_COLORS = {
1388
+ 30: "#45475a",
1389
+ 31: "#f38ba8",
1390
+ 32: "#a6e3a1",
1391
+ 33: "#f9e2af",
1392
+ 34: "#89b4fa",
1393
+ 35: "#f5c2e7",
1394
+ 36: "#94e2d5",
1395
+ 37: "#cdd6f4",
1396
+ 90: "#585b70",
1397
+ 91: "#f38ba8",
1398
+ 92: "#a6e3a1",
1399
+ 93: "#f9e2af",
1400
+ 94: "#89b4fa",
1401
+ 95: "#f5c2e7",
1402
+ 96: "#94e2d5",
1403
+ 97: "#cdd6f4"
1404
+ };
1405
+ var ANSI_RE = new RegExp(`${String.fromCharCode(27)}\\[([0-9;]*)m`, "g");
1406
+ function ansiToHtml(str) {
1407
+ let bold = false;
1408
+ let dim = false;
1409
+ let italic = false;
1410
+ let underline = false;
1411
+ let strikethrough = false;
1412
+ let color;
1413
+ let isOpen = false;
1414
+ function buildSpan() {
1415
+ const styles = [];
1416
+ if (bold) styles.push("font-weight:bold");
1417
+ if (dim) styles.push("opacity:0.6");
1418
+ if (italic) styles.push("font-style:italic");
1419
+ if (underline) styles.push("text-decoration:underline");
1420
+ if (strikethrough) styles.push("text-decoration:line-through");
1421
+ if (color) styles.push(`color:${color}`);
1422
+ if (!styles.length) return "";
1423
+ isOpen = true;
1424
+ return `<span style="${styles.join(";")}">`;
1425
+ }
1426
+ function closeIfOpen() {
1427
+ if (!isOpen) return "";
1428
+ isOpen = false;
1429
+ return "</span>";
1430
+ }
1431
+ let html = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1432
+ html = html.replace(ANSI_RE, (_, codes) => {
1433
+ const parts = codes.split(";").filter(Boolean).map(Number);
1434
+ if (parts.length === 0 || parts.includes(0)) {
1435
+ bold = false;
1436
+ dim = false;
1437
+ italic = false;
1438
+ underline = false;
1439
+ strikethrough = false;
1440
+ color = void 0;
1441
+ return closeIfOpen();
1442
+ }
1443
+ const close = closeIfOpen();
1444
+ for (const code of parts) {
1445
+ if (code === 1) bold = true;
1446
+ else if (code === 2) dim = true;
1447
+ else if (code === 3) italic = true;
1448
+ else if (code === 4) underline = true;
1449
+ else if (code === 9) strikethrough = true;
1450
+ else if (code === 22) {
1451
+ bold = false;
1452
+ dim = false;
1453
+ } else if (code === 23) italic = false;
1454
+ else if (code === 24) underline = false;
1455
+ else if (code === 29) strikethrough = false;
1456
+ else if (code === 39) color = void 0;
1457
+ else if (ANSI_COLORS[code]) color = ANSI_COLORS[code];
1458
+ }
1459
+ return close + buildSpan();
1460
+ });
1461
+ html += closeIfOpen();
1462
+ return html;
1463
+ }
1464
+ function buildErrorPageHtml(ansiError) {
1465
+ const errorContent = ansiError ? ansiToHtml(ansiError) : "Config is invalid \u2014 check your terminal for details.";
1466
+ return `<!DOCTYPE html>
1467
+ <html><head><title>varlock - config error</title></head>
1468
+ <body style="font-family: monospace; background: #1e1e2e; color: #cdd6f4; margin: 0; padding: 2rem;">
1469
+ <div style="margin-bottom: 1.5rem;">
1470
+ <h2 style="color: #f38ba8; margin: 0 0 0.5rem 0;">\u{1F512} Varlock \u2014 env config validation failed</h2>
1471
+ <p style="color: #6c7086; margin: 0;">Your environment variables are loaded and validated by <a href="https://varlock.dev" style="color: #89b4fa;">varlock</a>. Fix the error(s) below and save to reload.</p>
1472
+ </div>
1473
+ <pre style="white-space: pre-wrap; word-wrap: break-word; line-height: 1.5; background: #181825; padding: 1rem; border-radius: 8px;">${errorContent}</pre>
1474
+ </body></html>`;
1475
+ }
1387
1476
  globalThis.__varlockThrowOnMissingKeys = true;
1388
1477
  var originalProcessEnv = { ...process.env };
1389
1478
  var debug = createDebug("varlock:vite-integration");
1390
- var isFirstLoad = !process.__VARLOCK_ENV;
1391
- debug("varlock vite plugin loaded. first load = ", isFirstLoad);
1479
+ debug("varlock vite plugin loaded");
1392
1480
  var isDevCommand;
1393
1481
  var configIsValid = true;
1394
1482
  var varlockLoadedEnv;
1483
+ var varlockLastError;
1484
+ var lastErrorAt = 0;
1485
+ var configHookCalled = false;
1395
1486
  var staticReplacements = {};
1396
1487
  var replacerFn;
1397
1488
  function resetStaticReplacements() {
@@ -1419,16 +1510,28 @@ function reloadConfig(cwd) {
1419
1510
  });
1420
1511
  process.env.__VARLOCK_ENV = stdout;
1421
1512
  varlockLoadedEnv = JSON.parse(stdout);
1513
+ varlockLastError = void 0;
1514
+ lastErrorAt = 0;
1422
1515
  configIsValid = true;
1423
1516
  } catch (err) {
1424
1517
  if (err instanceof VarlockExecError) {
1425
1518
  if (err.stdout) {
1426
1519
  try {
1427
1520
  varlockLoadedEnv = JSON.parse(err.stdout);
1521
+ process.env.__VARLOCK_ENV = err.stdout;
1428
1522
  } catch {
1429
1523
  }
1430
1524
  }
1431
- if (err.stderr) console.error(err.stderr);
1525
+ if (err.stderr) {
1526
+ const now = Date.now();
1527
+ const isDuplicate = err.stderr === varlockLastError && now - lastErrorAt < 5e3;
1528
+ varlockLastError = err.stderr;
1529
+ lastErrorAt = now;
1530
+ if (!isDuplicate) {
1531
+ console.error(err.stderr);
1532
+ console.error("\n[varlock] \u26A0\uFE0F config is invalid \u2014 fix the error(s) above to continue\n");
1533
+ }
1534
+ }
1432
1535
  }
1433
1536
  configIsValid = false;
1434
1537
  resetStaticReplacements();
@@ -1483,7 +1586,7 @@ function varlockVitePlugin(vitePluginOptions) {
1483
1586
  },
1484
1587
  // hook to modify config before it is resolved
1485
1588
  async config(config, env) {
1486
- debug("vite plugin - config fn called");
1589
+ debug("vite plugin - config fn called, loadCount =", loadCount, "command =", env.command);
1487
1590
  if (config.envDir) {
1488
1591
  console.warn(`
1489
1592
  [varlock] \u26A0\uFE0F The \`envDir\` Vite option is not supported by varlock.
@@ -1503,8 +1606,8 @@ See https://varlock.dev/integrations/vite/ for more details.
1503
1606
  const rootDiffersFromCwd = !!(projectRoot && path2.relative(projectRoot, process.cwd()) !== "");
1504
1607
  if (rootDiffersFromCwd) {
1505
1608
  reloadConfig(projectRoot);
1506
- } else if (isFirstLoad) {
1507
- isFirstLoad = false;
1609
+ } else if (!configHookCalled) {
1610
+ configHookCalled = true;
1508
1611
  } else if (isDevCommand) {
1509
1612
  reloadConfig();
1510
1613
  }
@@ -1512,17 +1615,7 @@ See https://varlock.dev/integrations/vite/ for more details.
1512
1615
  if (isDevCommand) {
1513
1616
  config.clearScreen = false;
1514
1617
  } else {
1515
- console.log("\u{1F4A5} Varlock config validation failed \u{1F4A5}");
1516
- if (varlockLoadedEnv?.errors?.root) {
1517
- for (const msg of varlockLoadedEnv.errors.root) {
1518
- console.log(` - ${msg}`);
1519
- }
1520
- }
1521
- if (varlockLoadedEnv?.errors?.configItems) {
1522
- for (const [key, msg] of Object.entries(varlockLoadedEnv.errors.configItems)) {
1523
- console.log(` - ${key}: ${msg}`);
1524
- }
1525
- }
1618
+ console.error("\n[varlock] config is invalid \u2014 cannot proceed with build\n");
1526
1619
  process.exit(1);
1527
1620
  }
1528
1621
  }
@@ -1541,19 +1634,13 @@ See https://varlock.dev/integrations/vite/ for more details.
1541
1634
  // hook to configure vite dev server
1542
1635
  async configureServer(server) {
1543
1636
  debug("vite plugin - configureServer fn called");
1544
- if (!configIsValid) {
1545
- server.middlewares.use((req, res, next) => {
1546
- server.hot.send({
1547
- type: "error",
1548
- err: {
1549
- plugin: "varlock",
1550
- message: "Your config is currently invalid - check your terminal for more details",
1551
- stack: ""
1552
- }
1553
- });
1554
- return next();
1555
- });
1556
- }
1637
+ server.middlewares.use((req, res, next) => {
1638
+ if (configIsValid) return next();
1639
+ if (req.url?.startsWith("/@")) return next();
1640
+ res.statusCode = 500;
1641
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
1642
+ res.end(buildErrorPageHtml(varlockLastError));
1643
+ });
1557
1644
  },
1558
1645
  transform(code, id, options) {
1559
1646
  let magicString = replacerFn(this, code, id);
@@ -1607,19 +1694,9 @@ See https://varlock.dev/integrations/vite/ for more details.
1607
1694
  // this enables replacing %ENV.xxx% constants in html entry-point files
1608
1695
  // see https://vite.dev/guide/env-and-mode.html#html-constant-replacement
1609
1696
  transformIndexHtml(html) {
1697
+ debug("transformIndexHtml called, configIsValid =", configIsValid);
1610
1698
  if (!configIsValid) {
1611
- return `
1612
- <html>
1613
- <head>
1614
- <script type="module" src="/@vite/client"></script>
1615
- <title>Invalid config</title>
1616
- </head>
1617
- <body>
1618
- <h2>Your varlock config is currently invalid!</h2>
1619
- <p>Check your terminal for more details</p>
1620
- </body>
1621
- </html>
1622
- `;
1699
+ return buildErrorPageHtml(varlockLastError);
1623
1700
  }
1624
1701
  const replacedHtml = html.replace(
1625
1702
  // look for "%ENV.xxx%"
@@ -1803,16 +1880,20 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1803
1880
  userResult = userConfig;
1804
1881
  }
1805
1882
  if (!isDevMode) return userResult;
1806
- const { stdout: serializedGraph } = execSyncVarlock("load --format json-full --compact", { fullResult: true });
1807
- let graph;
1808
- try {
1809
- graph = JSON.parse(serializedGraph);
1810
- } catch (err) {
1811
- throw new Error(`[varlock] failed to parse config graph: ${err.message}`);
1883
+ const serializedGraph = process.env.__VARLOCK_ENV;
1884
+ if (!varlockLoadedEnv || !serializedGraph || varlockLoadedEnv.errors) {
1885
+ return {
1886
+ ...userResult,
1887
+ vars: {
1888
+ ...cfg.vars,
1889
+ ...userResult?.vars,
1890
+ ...serializedGraph && { __VARLOCK_ENV: serializedGraph }
1891
+ }
1892
+ };
1812
1893
  }
1813
1894
  const vars = {};
1814
- for (const key in graph.config) {
1815
- const { value } = graph.config[key];
1895
+ for (const key in varlockLoadedEnv.config) {
1896
+ const { value } = varlockLoadedEnv.config[key];
1816
1897
  if (value === void 0) continue;
1817
1898
  vars[key] = typeof value === "string" ? value : JSON.stringify(value);
1818
1899
  }
@@ -1826,6 +1907,19 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1826
1907
  }
1827
1908
  };
1828
1909
  };
1910
+ const errorPagePlugin = {
1911
+ name: "varlock-cloudflare-error-page",
1912
+ configureServer(server) {
1913
+ return () => {
1914
+ server.middlewares.use((req, res, next) => {
1915
+ if (!varlockLoadedEnv?.errors) return next();
1916
+ res.statusCode = 500;
1917
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
1918
+ res.end(buildErrorPageHtml(varlockLastError));
1919
+ });
1920
+ };
1921
+ }
1922
+ };
1829
1923
  const varlockPlugin = varlockVitePlugin({
1830
1924
  ssrEntryModuleIds: ["\0virtual:cloudflare/worker-entry"],
1831
1925
  ssrEntryCode: [CLOUDFLARE_SSR_ENTRY_CODE]
@@ -1872,6 +1966,7 @@ function varlockCloudflareVitePlugin(cloudflareOptions) {
1872
1966
  conflictGuard,
1873
1967
  modeDetector,
1874
1968
  previewEnvInjector,
1969
+ errorPagePlugin,
1875
1970
  varlockPlugin,
1876
1971
  // cloudflare() may return a single plugin or an array
1877
1972
  ...Array.isArray(cloudflarePlugin) ? cloudflarePlugin : [cloudflarePlugin]