appfunnel 0.11.0 → 0.12.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.
package/dist/index.js CHANGED
@@ -485,7 +485,7 @@ ${itemsStr},
485
485
  }
486
486
  writeFileSync2(configPath, config);
487
487
  }
488
- const sdkVersion = `^${"0.11.0"}`;
488
+ const sdkVersion = `^${"0.12.0"}`;
489
489
  writeFileSync2(
490
490
  join2(dir, "package.json"),
491
491
  JSON.stringify(
@@ -731,7 +731,7 @@ var init_config = __esm({
731
731
  import { readFileSync as readFileSync4 } from "fs";
732
732
  import { join as join4 } from "path";
733
733
  function checkVersionCompatibility(cwd) {
734
- const cliVersion = "0.11.0";
734
+ const cliVersion = "0.12.0";
735
735
  const sdkVersion = getSdkVersion(cwd);
736
736
  const [cliMajor, cliMinor] = cliVersion.split(".").map(Number);
737
737
  const [sdkMajor, sdkMinor] = sdkVersion.split(".").map(Number);
@@ -1448,6 +1448,386 @@ var init_dev = __esm({
1448
1448
  }
1449
1449
  });
1450
1450
 
1451
+ // src/lib/computeFlow.ts
1452
+ function computeFunnelFlow(pages, initialPageKey) {
1453
+ const allPageKeys = new Set(Object.keys(pages));
1454
+ if (allPageKeys.size === 0) {
1455
+ return { initialPageKey, segments: [], terminalPageKeys: [], unreachablePageKeys: [] };
1456
+ }
1457
+ function getTargets(pageKey) {
1458
+ const routes = pages[pageKey]?.routes || [];
1459
+ const seen = /* @__PURE__ */ new Set();
1460
+ const targets = [];
1461
+ for (const route of routes) {
1462
+ if (allPageKeys.has(route.to) && !seen.has(route.to)) {
1463
+ seen.add(route.to);
1464
+ targets.push(route.to);
1465
+ }
1466
+ }
1467
+ return targets;
1468
+ }
1469
+ const reachable = /* @__PURE__ */ new Set();
1470
+ {
1471
+ const queue = [];
1472
+ if (allPageKeys.has(initialPageKey)) {
1473
+ reachable.add(initialPageKey);
1474
+ queue.push(initialPageKey);
1475
+ }
1476
+ while (queue.length > 0) {
1477
+ const pageKey = queue.shift();
1478
+ for (const target of getTargets(pageKey)) {
1479
+ if (!reachable.has(target)) {
1480
+ reachable.add(target);
1481
+ queue.push(target);
1482
+ }
1483
+ }
1484
+ }
1485
+ }
1486
+ const unreachablePageKeys = [];
1487
+ const terminalPageKeys = [];
1488
+ for (const pageKey of allPageKeys) {
1489
+ if (!reachable.has(pageKey)) {
1490
+ unreachablePageKeys.push(pageKey);
1491
+ continue;
1492
+ }
1493
+ if (getTargets(pageKey).length === 0) {
1494
+ terminalPageKeys.push(pageKey);
1495
+ }
1496
+ }
1497
+ function bfsForward(start) {
1498
+ const dist = /* @__PURE__ */ new Map();
1499
+ dist.set(start, 0);
1500
+ const queue = [start];
1501
+ while (queue.length > 0) {
1502
+ const current2 = queue.shift();
1503
+ const d = dist.get(current2);
1504
+ for (const target of getTargets(current2)) {
1505
+ if (!dist.has(target)) {
1506
+ dist.set(target, d + 1);
1507
+ queue.push(target);
1508
+ }
1509
+ }
1510
+ }
1511
+ return dist;
1512
+ }
1513
+ function findConvergence(armStarts) {
1514
+ if (armStarts.length === 0) return null;
1515
+ const armReachable = armStarts.map((s) => bfsForward(s));
1516
+ const armStartSet = new Set(armStarts);
1517
+ let candidates = /* @__PURE__ */ new Set();
1518
+ for (const key of armReachable[0].keys()) {
1519
+ if (!armStartSet.has(key)) candidates.add(key);
1520
+ }
1521
+ for (let i = 1; i < armReachable.length; i++) {
1522
+ const reachSet = new Set(armReachable[i].keys());
1523
+ candidates = new Set([...candidates].filter((k) => reachSet.has(k)));
1524
+ }
1525
+ if (candidates.size === 0) return null;
1526
+ let bestPage = null;
1527
+ let bestMinDist = Infinity;
1528
+ for (const pageKey of candidates) {
1529
+ const minDist = Math.min(...armReachable.map((r) => r.get(pageKey) ?? Infinity));
1530
+ if (minDist < bestMinDist) {
1531
+ bestMinDist = minDist;
1532
+ bestPage = pageKey;
1533
+ }
1534
+ }
1535
+ return bestPage;
1536
+ }
1537
+ function walkArm(start, convergence, globalVisited2) {
1538
+ if (convergence === null) {
1539
+ const pages2 = [];
1540
+ let current2 = start;
1541
+ while (true) {
1542
+ if (globalVisited2.has(current2)) break;
1543
+ globalVisited2.add(current2);
1544
+ pages2.push(current2);
1545
+ const targets = getTargets(current2);
1546
+ if (targets.length === 0) break;
1547
+ const next = targets.find((t) => !globalVisited2.has(t));
1548
+ if (!next) break;
1549
+ current2 = next;
1550
+ }
1551
+ return pages2;
1552
+ }
1553
+ const parent = /* @__PURE__ */ new Map();
1554
+ parent.set(start, null);
1555
+ const queue = [start];
1556
+ let found = false;
1557
+ while (queue.length > 0 && !found) {
1558
+ const current2 = queue.shift();
1559
+ for (const target of getTargets(current2)) {
1560
+ if (!parent.has(target)) {
1561
+ parent.set(target, current2);
1562
+ if (target === convergence) {
1563
+ found = true;
1564
+ break;
1565
+ }
1566
+ queue.push(target);
1567
+ }
1568
+ }
1569
+ }
1570
+ if (!found) {
1571
+ const pages2 = [];
1572
+ let current2 = start;
1573
+ while (true) {
1574
+ if (globalVisited2.has(current2)) break;
1575
+ globalVisited2.add(current2);
1576
+ pages2.push(current2);
1577
+ const targets = getTargets(current2);
1578
+ if (targets.length === 0) break;
1579
+ const next = targets.find((t) => !globalVisited2.has(t));
1580
+ if (!next) break;
1581
+ current2 = next;
1582
+ }
1583
+ return pages2;
1584
+ }
1585
+ const path = [];
1586
+ let node = convergence;
1587
+ while (node !== null && node !== start) {
1588
+ path.unshift(node);
1589
+ node = parent.get(node) ?? null;
1590
+ }
1591
+ path.unshift(start);
1592
+ if (path[path.length - 1] === convergence) {
1593
+ path.pop();
1594
+ }
1595
+ for (const p of path) {
1596
+ globalVisited2.add(p);
1597
+ }
1598
+ return path;
1599
+ }
1600
+ if (!allPageKeys.has(initialPageKey)) {
1601
+ return { initialPageKey, segments: [], terminalPageKeys, unreachablePageKeys };
1602
+ }
1603
+ const segments = [];
1604
+ const globalVisited = /* @__PURE__ */ new Set();
1605
+ let current = initialPageKey;
1606
+ let sharedPages = [];
1607
+ while (current !== null && !globalVisited.has(current)) {
1608
+ const targets = getTargets(current);
1609
+ if (targets.length === 0) {
1610
+ sharedPages.push(current);
1611
+ globalVisited.add(current);
1612
+ break;
1613
+ }
1614
+ const uniqueTargets = [...new Set(targets)];
1615
+ if (uniqueTargets.length === 1) {
1616
+ sharedPages.push(current);
1617
+ globalVisited.add(current);
1618
+ current = uniqueTargets[0];
1619
+ continue;
1620
+ }
1621
+ sharedPages.push(current);
1622
+ globalVisited.add(current);
1623
+ segments.push({ type: "shared", pageKeys: [...sharedPages] });
1624
+ sharedPages = [];
1625
+ const convergence = findConvergence(uniqueTargets);
1626
+ const arms = [];
1627
+ for (const armStart of uniqueTargets) {
1628
+ const armPages = walkArm(armStart, convergence, globalVisited);
1629
+ arms.push({ pageKeys: armPages });
1630
+ }
1631
+ segments.push({ type: "branch", sourcePageKey: current, arms });
1632
+ if (convergence !== null && !globalVisited.has(convergence)) {
1633
+ current = convergence;
1634
+ } else {
1635
+ current = null;
1636
+ }
1637
+ }
1638
+ if (sharedPages.length > 0) {
1639
+ segments.push({ type: "shared", pageKeys: sharedPages });
1640
+ }
1641
+ return { initialPageKey, segments, terminalPageKeys, unreachablePageKeys };
1642
+ }
1643
+ var init_computeFlow = __esm({
1644
+ "src/lib/computeFlow.ts"() {
1645
+ "use strict";
1646
+ }
1647
+ });
1648
+
1649
+ // src/commands/routes.ts
1650
+ var routes_exports = {};
1651
+ __export(routes_exports, {
1652
+ routesCommand: () => routesCommand
1653
+ });
1654
+ import pc7 from "picocolors";
1655
+ async function routesCommand() {
1656
+ const cwd = process.cwd();
1657
+ const s = spinner("Analyzing pages...");
1658
+ const config = await loadConfig(cwd);
1659
+ const pageKeys = scanPages(cwd);
1660
+ const pages = await extractPageDefinitions(cwd, pageKeys);
1661
+ s.stop();
1662
+ const flow = computeFunnelFlow(pages, config.initialPageKey);
1663
+ console.log();
1664
+ console.log(` ${pc7.bold(config.name)}`);
1665
+ console.log(` ${pc7.dim(`${pageKeys.length} pages`)}`);
1666
+ console.log();
1667
+ renderFlow(flow, pages);
1668
+ }
1669
+ function renderFlow(flow, pages) {
1670
+ const indent = " ";
1671
+ for (let i = 0; i < flow.segments.length; i++) {
1672
+ const segment = flow.segments[i];
1673
+ if (segment.type === "shared") {
1674
+ for (let j = 0; j < segment.pageKeys.length; j++) {
1675
+ const key = segment.pageKeys[j];
1676
+ const page = pages[key];
1677
+ const isStart = key === flow.initialPageKey;
1678
+ const isTerminal = flow.terminalPageKeys.includes(key);
1679
+ printPageBox(indent, key, page, isStart, isTerminal);
1680
+ const isLastInSegment = j === segment.pageKeys.length - 1;
1681
+ const hasNextSegment = i < flow.segments.length - 1;
1682
+ if ((!isLastInSegment || hasNextSegment) && !isTerminal) {
1683
+ printArrow(indent);
1684
+ }
1685
+ }
1686
+ } else {
1687
+ renderBranch(indent, segment, pages, flow);
1688
+ if (i < flow.segments.length - 1) {
1689
+ printArrow(indent);
1690
+ }
1691
+ }
1692
+ }
1693
+ if (flow.unreachablePageKeys.length > 0) {
1694
+ console.log();
1695
+ console.log(` ${pc7.yellow("\u26A0")} ${pc7.yellow("Unreachable pages:")}`);
1696
+ for (const key of flow.unreachablePageKeys) {
1697
+ const page = pages[key];
1698
+ console.log(` ${pc7.dim("\u2022")} ${key}${page?.name ? pc7.dim(` (${page.name})`) : ""}`);
1699
+ }
1700
+ }
1701
+ console.log();
1702
+ }
1703
+ function formatPageLabel(key, page, isStart, isTerminal) {
1704
+ const name = page?.name || key;
1705
+ const type = page?.type;
1706
+ const badges = [];
1707
+ if (isStart) badges.push(pc7.green("start"));
1708
+ if (isTerminal) badges.push(pc7.red("end"));
1709
+ if (type && type !== "default") badges.push(pc7.magenta(type));
1710
+ const label = key === name.toLowerCase().replace(/\s+/g, "-") ? name : `${name} ${pc7.dim(`(${key})`)}`;
1711
+ const badgeStr = badges.length > 0 ? " " + badges.map((b) => pc7.dim("[") + b + pc7.dim("]")).join(" ") : "";
1712
+ return label + badgeStr;
1713
+ }
1714
+ function printPageBox(indent, key, page, isStart, isTerminal) {
1715
+ const label = formatPageLabel(key, page, isStart, isTerminal);
1716
+ const rawLen = stripAnsi(label).length;
1717
+ const boxWidth = Math.max(rawLen + 2, 20);
1718
+ const padding = boxWidth - rawLen - 2;
1719
+ console.log(`${indent}\u250C${H.repeat(boxWidth)}\u2510`);
1720
+ console.log(`${indent}\u2502 ${label}${" ".repeat(padding)} \u2502`);
1721
+ console.log(`${indent}\u2514${H.repeat(boxWidth)}\u2518`);
1722
+ }
1723
+ function printArrow(indent) {
1724
+ console.log(`${indent} ${V}`);
1725
+ console.log(`${indent} \u25BC`);
1726
+ }
1727
+ function renderBranch(indent, segment, pages, flow) {
1728
+ const arms = segment.arms;
1729
+ const colWidths = arms.map((arm) => {
1730
+ const maxNameLen = Math.max(
1731
+ ...arm.pageKeys.map((key) => {
1732
+ const page = pages[key];
1733
+ const name = page?.name || key;
1734
+ const type = page?.type;
1735
+ const typeLen = type && type !== "default" ? ` [${type}]`.length : 0;
1736
+ return name.length + typeLen;
1737
+ }),
1738
+ 8
1739
+ );
1740
+ return maxNameLen + 4;
1741
+ });
1742
+ let splitLine = "";
1743
+ for (let a = 0; a < arms.length; a++) {
1744
+ const mid = Math.floor(colWidths[a] / 2);
1745
+ if (a === 0) {
1746
+ splitLine += " ".repeat(mid) + "\u251C" + H.repeat(colWidths[a] - mid - 1);
1747
+ } else if (a === arms.length - 1) {
1748
+ splitLine += H.repeat(mid) + "\u2524" + " ".repeat(colWidths[a] - mid - 1);
1749
+ } else {
1750
+ splitLine += H.repeat(mid) + "\u252C" + H.repeat(colWidths[a] - mid - 1);
1751
+ }
1752
+ if (a < arms.length - 1) splitLine += H.repeat(3);
1753
+ }
1754
+ console.log(`${indent}${splitLine}`);
1755
+ let pipeLine = "";
1756
+ for (let a = 0; a < arms.length; a++) {
1757
+ const mid = Math.floor(colWidths[a] / 2);
1758
+ pipeLine += " ".repeat(mid) + V + " ".repeat(colWidths[a] - mid - 1);
1759
+ if (a < arms.length - 1) pipeLine += " ";
1760
+ }
1761
+ console.log(`${indent}${pipeLine}`);
1762
+ const maxDepth = Math.max(...arms.map((a) => a.pageKeys.length));
1763
+ for (let row = 0; row < maxDepth; row++) {
1764
+ let line = "";
1765
+ for (let a = 0; a < arms.length; a++) {
1766
+ const key = arms[a].pageKeys[row];
1767
+ const mid = Math.floor(colWidths[a] / 2);
1768
+ if (key) {
1769
+ const page = pages[key];
1770
+ const name = page?.name || key;
1771
+ const type = page?.type;
1772
+ const typeBadge = type && type !== "default" ? " " + pc7.magenta(`[${type}]`) : "";
1773
+ const display = name + typeBadge;
1774
+ const displayLen = stripAnsi(display).length;
1775
+ const truncated = displayLen > colWidths[a] - 2 ? name.slice(0, colWidths[a] - 5) + "..." : display;
1776
+ const truncLen = stripAnsi(truncated).length;
1777
+ const leftPad = mid - Math.floor(truncLen / 2);
1778
+ const rightPad = colWidths[a] - leftPad - truncLen;
1779
+ line += " ".repeat(Math.max(0, leftPad)) + pc7.bold(truncated) + " ".repeat(Math.max(0, rightPad));
1780
+ } else {
1781
+ line += " ".repeat(colWidths[a]);
1782
+ }
1783
+ if (a < arms.length - 1) line += " ";
1784
+ }
1785
+ console.log(`${indent}${line}`);
1786
+ if (row < maxDepth - 1) {
1787
+ let connector = "";
1788
+ for (let a = 0; a < arms.length; a++) {
1789
+ const mid = Math.floor(colWidths[a] / 2);
1790
+ const hasMore = row + 1 < arms[a].pageKeys.length;
1791
+ if (hasMore) {
1792
+ connector += " ".repeat(mid) + "\u25BC" + " ".repeat(colWidths[a] - mid - 1);
1793
+ } else {
1794
+ connector += " ".repeat(colWidths[a]);
1795
+ }
1796
+ if (a < arms.length - 1) connector += " ";
1797
+ }
1798
+ console.log(`${indent}${connector}`);
1799
+ }
1800
+ }
1801
+ let mergeLine = "";
1802
+ for (let a = 0; a < arms.length; a++) {
1803
+ const mid = Math.floor(colWidths[a] / 2);
1804
+ if (a === 0) {
1805
+ mergeLine += " ".repeat(mid) + "\u251C" + H.repeat(colWidths[a] - mid - 1);
1806
+ } else if (a === arms.length - 1) {
1807
+ mergeLine += H.repeat(mid) + "\u2524" + " ".repeat(colWidths[a] - mid - 1);
1808
+ } else {
1809
+ mergeLine += H.repeat(mid) + "\u2534" + H.repeat(colWidths[a] - mid - 1);
1810
+ }
1811
+ if (a < arms.length - 1) mergeLine += H.repeat(3);
1812
+ }
1813
+ console.log(`${indent}${mergeLine}`);
1814
+ }
1815
+ function stripAnsi(str) {
1816
+ return str.replace(/\x1b\[[0-9;]*m/g, "");
1817
+ }
1818
+ var H, V;
1819
+ var init_routes = __esm({
1820
+ "src/commands/routes.ts"() {
1821
+ "use strict";
1822
+ init_logger();
1823
+ init_config();
1824
+ init_pages();
1825
+ init_computeFlow();
1826
+ H = "\u2500";
1827
+ V = "\u2502";
1828
+ }
1829
+ });
1830
+
1451
1831
  // src/commands/build.ts
1452
1832
  var build_exports = {};
1453
1833
  __export(build_exports, {
@@ -1456,7 +1836,7 @@ __export(build_exports, {
1456
1836
  import { resolve as resolve3, join as join9 } from "path";
1457
1837
  import { randomUUID as randomUUID2 } from "crypto";
1458
1838
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, statSync, readdirSync as readdirSync4 } from "fs";
1459
- import pc7 from "picocolors";
1839
+ import pc8 from "picocolors";
1460
1840
  async function buildCommand() {
1461
1841
  const cwd = process.cwd();
1462
1842
  requireAuth();
@@ -1579,14 +1959,14 @@ async function buildCommand() {
1579
1959
  console.log();
1580
1960
  success("Build complete");
1581
1961
  console.log();
1582
- console.log(` ${pc7.dim("Output:")} dist/`);
1583
- console.log(` ${pc7.dim("Pages:")} ${pageKeys.length}`);
1584
- console.log(` ${pc7.dim("Size:")} ${formatSize(totalSize)}`);
1962
+ console.log(` ${pc8.dim("Output:")} dist/`);
1963
+ console.log(` ${pc8.dim("Pages:")} ${pageKeys.length}`);
1964
+ console.log(` ${pc8.dim("Size:")} ${formatSize(totalSize)}`);
1585
1965
  console.log();
1586
1966
  for (const asset of assets) {
1587
1967
  const sizeStr = formatSize(asset.size);
1588
1968
  const isOver = asset.size > MAX_PAGE_SIZE;
1589
- console.log(` ${isOver ? pc7.yellow("!") : pc7.dim("\xB7")} ${pc7.dim(asset.path)} ${isOver ? pc7.yellow(sizeStr) : pc7.dim(sizeStr)}`);
1969
+ console.log(` ${isOver ? pc8.yellow("!") : pc8.dim("\xB7")} ${pc8.dim(asset.path)} ${isOver ? pc8.yellow(sizeStr) : pc8.dim(sizeStr)}`);
1590
1970
  }
1591
1971
  console.log();
1592
1972
  if (totalSize > MAX_TOTAL_SIZE) {
@@ -1755,7 +2135,7 @@ __export(publish_exports, {
1755
2135
  });
1756
2136
  import { resolve as resolve4, join as join11 } from "path";
1757
2137
  import { readFileSync as readFileSync10, existsSync as existsSync6 } from "fs";
1758
- import pc8 from "picocolors";
2138
+ import pc9 from "picocolors";
1759
2139
  function getMimeType(path) {
1760
2140
  const ext = path.substring(path.lastIndexOf("."));
1761
2141
  return MIME_TYPES[ext] || "application/octet-stream";
@@ -1810,9 +2190,9 @@ async function publishCommand(options) {
1810
2190
  content,
1811
2191
  contentType: getMimeType(asset.path)
1812
2192
  });
1813
- s.text = `Preparing assets... ${i + 1}/${assets.length} ${pc8.dim(`(${formatSize2(totalBytes)})`)}`;
2193
+ s.text = `Preparing assets... ${i + 1}/${assets.length} ${pc9.dim(`(${formatSize2(totalBytes)})`)}`;
1814
2194
  }
1815
- s.text = `Uploading ${assets.length} assets ${pc8.dim(`(${formatSize2(totalBytes)})`)}`;
2195
+ s.text = `Uploading ${assets.length} assets ${pc9.dim(`(${formatSize2(totalBytes)})`)}`;
1816
2196
  const result = await publishBuild(
1817
2197
  projectId,
1818
2198
  config.funnelId || "",
@@ -1829,15 +2209,15 @@ async function publishCommand(options) {
1829
2209
  console.log();
1830
2210
  success(result.activated ? "Published and activated" : "Published successfully");
1831
2211
  console.log();
1832
- console.log(` ${pc8.dim("Build ID:")} ${result.buildId}`);
2212
+ console.log(` ${pc9.dim("Build ID:")} ${result.buildId}`);
1833
2213
  if (result.funnelId && !config.funnelId) {
1834
- console.log(` ${pc8.dim("Funnel:")} ${result.funnelId}`);
2214
+ console.log(` ${pc9.dim("Funnel:")} ${result.funnelId}`);
1835
2215
  }
1836
- console.log(` ${pc8.dim("Dashboard:")} ${pc8.cyan(result.dashboardUrl)}`);
1837
- console.log(` ${pc8.dim("Assets:")} ${assets.length} files ${pc8.dim(`(${formatSize2(totalBytes)})`)}`);
2216
+ console.log(` ${pc9.dim("Dashboard:")} ${pc9.cyan(result.dashboardUrl)}`);
2217
+ console.log(` ${pc9.dim("Assets:")} ${assets.length} files ${pc9.dim(`(${formatSize2(totalBytes)})`)}`);
1838
2218
  if (!result.activated) {
1839
2219
  console.log();
1840
- console.log(` ${pc8.dim("Tip:")} Use ${pc8.cyan("--promote")} to activate immediately, or promote from the dashboard.`);
2220
+ console.log(` ${pc9.dim("Tip:")} Use ${pc9.cyan("--promote")} to activate immediately, or promote from the dashboard.`);
1841
2221
  }
1842
2222
  console.log();
1843
2223
  }
@@ -1869,9 +2249,9 @@ var init_publish = __esm({
1869
2249
  // src/index.ts
1870
2250
  init_errors();
1871
2251
  import { Command } from "commander";
1872
- import pc9 from "picocolors";
2252
+ import pc10 from "picocolors";
1873
2253
  var program = new Command();
1874
- program.name("appfunnel").description("Build and publish headless AppFunnel projects").version("0.11.0");
2254
+ program.name("appfunnel").description("Build and publish headless AppFunnel projects").version("0.12.0");
1875
2255
  program.command("init").argument("[name]", "Project directory name").description("Create a new AppFunnel project").action(async (name) => {
1876
2256
  const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
1877
2257
  await initCommand2(name);
@@ -1888,6 +2268,10 @@ program.command("dev").description("Start the development server").option("-p, -
1888
2268
  const { devCommand: devCommand2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
1889
2269
  await devCommand2({ port: parseInt(options.port, 10) });
1890
2270
  });
2271
+ program.command("routes").description("Visualize the funnel page flow").action(async () => {
2272
+ const { routesCommand: routesCommand2 } = await Promise.resolve().then(() => (init_routes(), routes_exports));
2273
+ await routesCommand2();
2274
+ });
1891
2275
  program.command("build").description("Build the funnel for production").action(async () => {
1892
2276
  const { buildCommand: buildCommand2 } = await Promise.resolve().then(() => (init_build(), build_exports));
1893
2277
  await buildCommand2();
@@ -1906,9 +2290,9 @@ async function main() {
1906
2290
  console.error(formatError(err));
1907
2291
  process.exit(1);
1908
2292
  }
1909
- console.error(`${pc9.red("ERROR")}: ${err instanceof Error ? err.message : String(err)}`);
2293
+ console.error(`${pc10.red("ERROR")}: ${err instanceof Error ? err.message : String(err)}`);
1910
2294
  if (err instanceof Error && err.stack) {
1911
- console.error(pc9.dim(err.stack));
2295
+ console.error(pc10.dim(err.stack));
1912
2296
  }
1913
2297
  process.exit(1);
1914
2298
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/errors.ts","../src/lib/logger.ts","../src/lib/auth.ts","../src/lib/projects.ts","../src/lib/api.ts","../src/commands/init.ts","../src/commands/login.ts","../src/commands/whoami.ts","../src/lib/config.ts","../src/lib/version.ts","../src/extract/pages.ts","../src/vite/entry.ts","../src/vite/html.ts","../src/vite/plugin.ts","../src/commands/dev.ts","../src/commands/build.ts","../src/lib/config-patch.ts","../src/commands/publish.ts","../src/index.ts"],"sourcesContent":["import pc from 'picocolors'\n\nexport type ErrorCode =\n\t| 'AUTH_REQUIRED'\n\t| 'AUTH_EXPIRED'\n\t| 'CONFIG_NOT_FOUND'\n\t| 'INVALID_ROUTE'\n\t| 'UNDEFINED_VARIABLE'\n\t| 'VERSION_MISMATCH'\n\t| 'BUILD_NOT_FOUND'\n\t| 'FUNNEL_NOT_HEADLESS'\n\t| 'BUNDLE_TOO_LARGE'\n\t| 'PAGE_SIZE'\n\t| 'INVALID_PAGE'\n\t| 'NO_PAGES'\n\t| 'NO_PROJECTS'\n\t| 'MISSING_PROJECT_ID'\n\t| 'MISSING_INITIAL_PAGE_KEY'\n\t| 'API_ERROR'\n\t| 'PUBLISH_FAILED'\n\nexport class CLIError extends Error {\n\tcode: ErrorCode\n\thint?: string\n\tstatusCode?: number\n\n\tconstructor(code: ErrorCode, message: string, hint?: string) {\n\t\tsuper(message)\n\t\tthis.name = 'CLIError'\n\t\tthis.code = code\n\t\tthis.hint = hint\n\t}\n}\n\nexport function formatError(err: CLIError): string {\n\tconst lines = [\n\t\t`${pc.red('ERROR')} ${pc.dim(`[${err.code}]`)}: ${err.message}`,\n\t]\n\tif (err.hint) {\n\t\tlines.push(` ${pc.dim('Hint:')} ${err.hint}`)\n\t}\n\treturn lines.join('\\n')\n}\n\nexport function formatWarning(\n\tcode: string,\n\tmessage: string,\n\thint?: string\n): string {\n\tconst lines = [`${pc.yellow('WARNING')} ${pc.dim(`[${code}]`)}: ${message}`]\n\tif (hint) {\n\t\tlines.push(` ${pc.dim('Hint:')} ${hint}`)\n\t}\n\treturn lines.join('\\n')\n}\n","import pc from 'picocolors'\nimport ora, { type Ora } from 'ora'\n\nexport function success(msg: string): void {\n console.log(`${pc.green('✓')} ${msg}`)\n}\n\nexport function error(msg: string): void {\n console.error(`${pc.red('✗')} ${msg}`)\n}\n\nexport function warn(msg: string): void {\n console.warn(`${pc.yellow('!')} ${msg}`)\n}\n\nexport function info(msg: string): void {\n console.log(`${pc.blue('ℹ')} ${msg}`)\n}\n\nexport function dim(msg: string): void {\n console.log(pc.dim(msg))\n}\n\nexport function spinner(msg: string): Ora {\n return ora({ text: msg, color: 'cyan' }).start()\n}\n\nexport function banner(): void {\n console.log()\n console.log(` ${pc.bold('appfunnel')} ${pc.dim('v' + __CLI_VERSION__)}`)\n console.log()\n}\n","import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport { CLIError } from './errors.js'\n\nexport interface Credentials {\n token: string\n userId: string\n email: string\n expiresAt: string\n}\n\nconst CREDENTIALS_PATH = join(homedir(), '.appfunnelrc')\n\nexport function readCredentials(): Credentials | null {\n try {\n const raw = readFileSync(CREDENTIALS_PATH, 'utf-8')\n const data = JSON.parse(raw)\n if (!data.token) return null\n return data as Credentials\n } catch {\n return null\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const dir = homedir()\n mkdirSync(dir, { recursive: true })\n writeFileSync(CREDENTIALS_PATH, JSON.stringify(creds, null, 2) + '\\n', 'utf-8')\n}\n\nexport function requireAuth(): Credentials {\n const creds = readCredentials()\n if (!creds) {\n throw new CLIError(\n 'AUTH_REQUIRED',\n 'Not logged in.',\n \"Run 'appfunnel login' to authenticate.\",\n )\n }\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt)\n if (expiresAt < new Date()) {\n throw new CLIError(\n 'AUTH_EXPIRED',\n 'Token expired.',\n \"Run 'appfunnel login' to re-authenticate.\",\n )\n }\n }\n\n return creds\n}\n","import pc from 'picocolors'\nimport select from '@inquirer/select'\nimport * as log from './logger.js'\nimport { CLIError } from './errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\nexport interface Project {\n id: string\n name: string\n role: string\n}\n\nexport async function fetchProjects(token: string): Promise<Project[]> {\n const response = await fetch(`${DEFAULT_API_BASE}/user/projects`, {\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n throw new CLIError('API_ERROR', 'Failed to fetch projects.')\n }\n\n const body = (await response.json()) as { data: Project[] }\n return body.data\n}\n\n/**\n * Prompt the user to select a project from their available projects.\n * Returns the selected project ID.\n */\nexport async function promptForProject(token: string): Promise<string> {\n const spin = log.spinner('Fetching projects...')\n let projects: Project[]\n try {\n projects = await fetchProjects(token)\n } catch (err) {\n spin.stop()\n if (err instanceof CLIError) throw err\n throw new CLIError(\n 'API_ERROR',\n 'Failed to reach the API. Check your internet connection.',\n )\n }\n spin.stop()\n\n if (projects.length === 0) {\n throw new CLIError(\n 'NO_PROJECTS',\n 'No projects found.',\n 'Create a project at https://appfunnel.net first.',\n )\n }\n\n return select({\n message: 'Select a project',\n choices: projects.map((p) => ({\n name: `${p.name} ${pc.dim(`(${p.id})`)}`,\n value: p.id,\n })),\n })\n}\n","import { CLIError } from './errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\ninterface ApiOptions {\n\ttoken: string\n\tapiBaseUrl?: string\n}\n\nasync function apiFetch(\n\tpath: string,\n\toptions: ApiOptions & RequestInit\n): Promise<Response> {\n\tconst { token, apiBaseUrl, ...fetchOpts } = options\n\tconst base = apiBaseUrl || DEFAULT_API_BASE\n\tconst url = `${base}${path}`\n\n\t// Don't set Content-Type for FormData — let the browser set the boundary\n\tconst isFormData = fetchOpts.body instanceof FormData\n\tconst headers: Record<string, string> = {\n\t\tAuthorization: token,\n\t\t...((fetchOpts.headers as Record<string, string>) || {}),\n\t}\n\tif (!isFormData) {\n\t\theaders['Content-Type'] = 'application/json'\n\t}\n\n\tconst response = await fetch(url, {\n\t\t...fetchOpts,\n\t\theaders,\n\t})\n\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => '')\n\t\tlet message = `API request failed: ${response.status} ${response.statusText}`\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(body)\n\t\t\tif (parsed.error) message = parsed.error\n\t\t\tif (parsed.message) message = parsed.message\n\t\t} catch {\n\t\t\t/* ignore parse errors */\n\t\t}\n\t\tconst error = new CLIError('API_ERROR', message)\n\t\terror.statusCode = response.status\n\t\tthrow error\n\t}\n\n\treturn response\n}\n\n/**\n * Fetch enriched price data for all store price IDs.\n */\nexport async function fetchPrices(\n\tprojectId: string,\n\tstorePriceIds: string[],\n\toptions: ApiOptions\n): Promise<Map<string, unknown>> {\n\tif (storePriceIds.length === 0) return new Map()\n\n\tconst response = await apiFetch(`/project/${projectId}/headless/prices`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ storePriceIds }),\n\t})\n\n\tconst data = (await response.json()) as { prices: Record<string, unknown> }\n\treturn new Map(Object.entries(data.prices || {}))\n}\n\n/* ---------- Store & price listing (for template init) ---------- */\n\nexport interface Store {\n\tid: string\n\tname: string\n\ttype: 'STRIPE' | 'PADDLE'\n\tisTestMode: boolean\n}\n\nexport interface StorePrice {\n\tid: string\n\tstoreId: string\n\tname: string | null\n\tpriceName: string | null\n\tdisplayName: string | null\n\tamount: number\n\tcurrency: string\n\tinterval: string | null\n\tintervalCount: number\n}\n\n/**\n * Fetch all stores for a project.\n */\nexport async function fetchStores(\n\tprojectId: string,\n\toptions: ApiOptions\n): Promise<Store[]> {\n\tconst response = await apiFetch(`/project/${projectId}/stores`, {\n\t\t...options,\n\t\tmethod: 'GET',\n\t})\n\tconst data = (await response.json()) as { data: Store[] }\n\treturn data.data || []\n}\n\n/**\n * Fetch all prices for a store.\n */\nexport async function fetchStorePrices(\n\tprojectId: string,\n\tstoreId: string,\n\toptions: ApiOptions\n): Promise<StorePrice[]> {\n\tconst response = await apiFetch(\n\t\t`/project/${projectId}/stores/${storeId}/prices`,\n\t\t{ ...options, method: 'GET' }\n\t)\n\tconst data = (await response.json()) as { data: StorePrice[] }\n\treturn data.data || []\n}\n\n/**\n * Fetch all prices across all stores for a project.\n * Returns prices annotated with store info for display.\n */\nexport async function fetchAllProjectPrices(\n\tprojectId: string,\n\toptions: ApiOptions\n): Promise<Array<StorePrice & { store: Store }>> {\n\tconst stores = await fetchStores(projectId, options)\n\tconst all: Array<StorePrice & { store: Store }> = []\n\n\tfor (const store of stores) {\n\t\tconst prices = await fetchStorePrices(projectId, store.id, options)\n\t\tfor (const price of prices) {\n\t\t\tall.push({ ...price, store })\n\t\t}\n\t}\n\n\treturn all\n}\n\n/**\n * Publish a headless build.\n * If funnelId is empty, the server auto-creates a new headless funnel + campaign.\n */\nexport async function publishBuild(\n\tprojectId: string,\n\tfunnelId: string,\n\tmanifest: unknown,\n\tassets: Array<{ path: string; content: Buffer; contentType: string }>,\n\toptions: ApiOptions,\n\tpromote?: boolean\n): Promise<{ buildId: string; funnelId: string; created: boolean; activated: boolean; dashboardUrl: string; message: string }> {\n\tconst formData = new FormData()\n\tformData.set('manifest', JSON.stringify(manifest))\n\tif (funnelId) {\n\t\tformData.set('funnelId', funnelId)\n\t}\n\tif (promote) {\n\t\tformData.set('promote', 'true')\n\t}\n\n\tfor (const asset of assets) {\n\t\tformData.append(\n\t\t\t'assets',\n\t\t\tnew Blob([new Uint8Array(asset.content)], { type: asset.contentType }),\n\t\t\tasset.path\n\t\t)\n\t}\n\n\ttry {\n\t\tconst response = await apiFetch(`/project/${projectId}/headless/publish`, {\n\t\t\t...options,\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t})\n\t\treturn (await response.json()) as { buildId: string; funnelId: string; created: boolean; activated: boolean; dashboardUrl: string; message: string }\n\t} catch (err) {\n\t\tif (err instanceof CLIError && err.code === 'API_ERROR') {\n\t\t\tif (err.statusCode === 413) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'BUNDLE_TOO_LARGE',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Reduce page bundle sizes. Check for large dependencies.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (err.statusCode === 409) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'FUNNEL_NOT_HEADLESS',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Remove funnelId from config to create a new headless funnel.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow new CLIError('PUBLISH_FAILED', err.message)\n\t\t}\n\t\tthrow err\n\t}\n}\n","import { cpSync, existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport pc from 'picocolors'\nimport select from '@inquirer/select'\nimport input from '@inquirer/input'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { fetchProjects, promptForProject } from '../lib/projects.js'\nimport { fetchStores, fetchStorePrices, type Store, type StorePrice } from '../lib/api.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/* ---------- Template types ---------- */\n\ninterface TemplateProduct {\n\tid: string\n\tlabel: string\n\tdescription?: string\n\tpaidTrial?: boolean\n}\n\ninterface TemplateConfig {\n\tname: string\n\tdescription: string\n\tproducts: TemplateProduct[]\n}\n\n/* ---------- Helpers ---------- */\n\nfunction getTemplatesDir(): string {\n\tconst dir = join(__dirname, '..', 'templates')\n\tif (!existsSync(dir)) {\n\t\tthrow new Error(`Templates directory not found at ${dir}`)\n\t}\n\treturn dir\n}\n\nfunction listTemplates(): Array<{ dir: string; config: TemplateConfig }> {\n\tconst root = getTemplatesDir()\n\treturn readdirSync(root, { withFileTypes: true })\n\t\t.filter((d) => d.isDirectory())\n\t\t.map((d) => {\n\t\t\tconst configPath = join(root, d.name, 'template.json')\n\t\t\tconst config: TemplateConfig = existsSync(configPath)\n\t\t\t\t? JSON.parse(readFileSync(configPath, 'utf-8'))\n\t\t\t\t: { name: d.name, description: '', products: [] }\n\t\t\treturn { dir: d.name, config }\n\t\t})\n}\n\nconst INTERVAL_LABELS: Record<string, Record<number, string>> = {\n\tday: { 1: 'day', 7: 'week', 14: '2 weeks', 30: 'month' },\n\tweek: { 1: 'week', 2: '2 weeks', 4: 'month', 12: 'quarter', 52: 'year' },\n\tmonth: { 1: 'month', 3: 'quarter', 6: '6 months', 12: 'year' },\n\tyear: { 1: 'year' },\n}\n\nfunction formatInterval(interval: string | null, count: number): string {\n\tif (!interval) return ' one-time'\n\tconst label = INTERVAL_LABELS[interval]?.[count]\n\tif (label) return `/${label}`\n\treturn `/${count} ${interval}${count > 1 ? 's' : ''}`\n}\n\nfunction formatPrice(price: StorePrice): string {\n\tconst amount = (price.amount / 100).toFixed(2)\n\tconst currency = price.currency.toUpperCase()\n\tconst interval = formatInterval(price.interval, price.intervalCount)\n\n\tconst productName = price.name || 'Unnamed product'\n\tconst priceName = price.priceName ? ` — ${price.priceName}` : ''\n\n\treturn `${currency} ${amount}${interval} ${pc.dim(`${productName}${priceName}`)} ${pc.dim(`(${price.id})`)}`\n}\n\nfunction formatStoreName(store: Store): string {\n\tconst test = store.isTestMode ? pc.yellow(' (test)') : ''\n\treturn `${store.name || store.type}${test}`\n}\n\n/* ---------- Main ---------- */\n\nexport async function initCommand(nameArg?: string): Promise<void> {\n\tconst creds = requireAuth()\n\tconst apiOpts = { token: creds.token }\n\n\t// 1. Use provided name or ask interactively\n\tconst name = nameArg?.trim() || await input({\n\t\tmessage: 'Funnel name',\n\t\tvalidate: (value) => {\n\t\t\tif (!value.trim()) return 'Name is required'\n\t\t\tif (!/^[a-z0-9-]+$/.test(value.trim()))\n\t\t\t\treturn 'Use lowercase letters, numbers, and hyphens only'\n\t\t\tif (existsSync(join(process.cwd(), value.trim())))\n\t\t\t\treturn `Directory '${value.trim()}' already exists`\n\t\t\treturn true\n\t\t},\n\t})\n\n\t// Validate name if provided as argument\n\tif (nameArg) {\n\t\tif (!/^[a-z0-9-]+$/.test(name))\n\t\t\tthrow new Error('Name must be lowercase letters, numbers, and hyphens only')\n\t\tif (existsSync(join(process.cwd(), name)))\n\t\t\tthrow new Error(`Directory '${name}' already exists`)\n\t}\n\n\tconst dir = join(process.cwd(), name.trim())\n\n\t// 2. Select project\n\tconst projectId = await promptForProject(creds.token)\n\tconst projects = await fetchProjects(creds.token)\n\tconst project = projects.find((p) => p.id === projectId)!\n\n\t// 3. Select template\n\tconst templates = listTemplates()\n\tconst selectedDir = await select({\n\t\tmessage: 'Choose a template',\n\t\tchoices: templates.map((t) => ({\n\t\t\tname: t.config.description\n\t\t\t\t? `${t.config.name} — ${pc.dim(t.config.description)}`\n\t\t\t\t: t.config.name,\n\t\t\tvalue: t.dir,\n\t\t})),\n\t})\n\tconst chosen = templates.find((t) => t.dir === selectedDir)!\n\n\tconst templateConfig = chosen.config\n\tconst templateDir = join(getTemplatesDir(), chosen.dir)\n\n\t// 3. If template has products, select store + bind prices\n\tconst productBindings: Array<{\n\t\tid: string\n\t\tname: string\n\t\tstorePriceId: string\n\t\ttrialDays?: number\n\t\ttrialStorePriceId?: string\n\t}> = []\n\n\tif (templateConfig.products.length > 0) {\n\t\t// Fetch stores\n\t\tconst storesSpinner = log.spinner('Fetching stores...')\n\t\tconst stores = await fetchStores(projectId, apiOpts)\n\t\tstoresSpinner.stop()\n\n\t\tif (stores.length === 0) {\n\t\t\tlog.warn('No stores found for this project.')\n\t\t\tlog.info('Products will use empty IDs — create a store in the dashboard and update appfunnel.config.ts.')\n\t\t} else {\n\t\t\t// Select store\n\t\t\tlet store: Store\n\t\t\tif (stores.length === 1) {\n\t\t\t\tstore = stores[0]\n\t\t\t\tlog.info(`Using store: ${formatStoreName(store)}`)\n\t\t\t} else {\n\t\t\t\tconst storeId = await select({\n\t\t\t\t\tmessage: 'Choose a store',\n\t\t\t\t\tchoices: stores.map((s) => ({\n\t\t\t\t\t\tname: formatStoreName(s),\n\t\t\t\t\t\tvalue: s.id,\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tstore = stores.find((s) => s.id === storeId)!\n\t\t\t}\n\n\t\t\t// Fetch prices from selected store\n\t\t\tconst pricesSpinner = log.spinner('Fetching prices...')\n\t\t\tconst prices = await fetchStorePrices(projectId, store.id, apiOpts)\n\t\t\tpricesSpinner.stop()\n\n\t\t\tif (prices.length === 0) {\n\t\t\t\tlog.warn('No prices found in this store.')\n\t\t\t\tlog.info('Import prices in the dashboard, then update appfunnel.config.ts.')\n\t\t\t} else {\n\t\t\t\tconsole.log()\n\t\t\t\tlog.info(`Configuring ${templateConfig.products.length} product(s)...`)\n\t\t\t\tconsole.log()\n\n\t\t\t\tfor (const product of templateConfig.products) {\n\t\t\t\t\tif (product.description) {\n\t\t\t\t\t\tconsole.log(` ${pc.dim(product.description)}`)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Select main price\n\t\t\t\t\tconst storePriceId = await select({\n\t\t\t\t\t\tmessage: `${product.label} — select a price`,\n\t\t\t\t\t\tchoices: prices.map((p) => ({\n\t\t\t\t\t\t\tname: formatPrice(p),\n\t\t\t\t\t\t\tvalue: p.id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t})\n\n\t\t\t\t\tconst binding: (typeof productBindings)[number] = {\n\t\t\t\t\t\tid: product.id,\n\t\t\t\t\t\tname: product.id,\n\t\t\t\t\t\tstorePriceId,\n\t\t\t\t\t}\n\n\t\t\t\t\t// Select trial price if needed\n\t\t\t\t\tif (product.paidTrial) {\n\t\t\t\t\t\tconst trialStorePriceId = await select({\n\t\t\t\t\t\t\tmessage: `${product.label} — select a trial price`,\n\t\t\t\t\t\t\tchoices: [\n\t\t\t\t\t\t\t\t...prices.map((p) => ({\n\t\t\t\t\t\t\t\t\tname: formatPrice(p),\n\t\t\t\t\t\t\t\t\tvalue: p.id,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t{ name: pc.dim('Skip (no trial)'), value: '' },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\tif (trialStorePriceId) {\n\t\t\t\t\t\t\tbinding.trialStorePriceId = trialStorePriceId\n\n\t\t\t\t\t\t\tconst trialDaysStr = await select({\n\t\t\t\t\t\t\t\tmessage: `${product.label} — trial duration`,\n\t\t\t\t\t\t\t\tchoices: [\n\t\t\t\t\t\t\t\t\t{ name: '3 days', value: '3' },\n\t\t\t\t\t\t\t\t\t{ name: '7 days', value: '7' },\n\t\t\t\t\t\t\t\t\t{ name: '14 days', value: '14' },\n\t\t\t\t\t\t\t\t\t{ name: '30 days', value: '30' },\n\t\t\t\t\t\t\t\t\t{ name: '90 days', value: '90' },\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbinding.trialDays = parseInt(trialDaysStr, 10)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tproductBindings.push(binding)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Copy template\n\tconst s = log.spinner(`Creating ${name}...`)\n\n\tcpSync(templateDir, dir, { recursive: true })\n\n\t// Remove template.json from output — it's not part of the user's project\n\tconst templateJsonPath = join(dir, 'template.json')\n\tif (existsSync(templateJsonPath)) {\n\t\tconst { unlinkSync } = await import('node:fs')\n\t\tunlinkSync(templateJsonPath)\n\t}\n\n\t// npm strips .gitignore from published packages, so we ship it as 'gitignore' and rename here\n\tconst gitignoreSrc = join(dir, 'gitignore')\n\tif (existsSync(gitignoreSrc)) {\n\t\tconst { renameSync } = await import('node:fs')\n\t\trenameSync(gitignoreSrc, join(dir, '.gitignore'))\n\t}\n\n\t// 5. Replace placeholders in appfunnel.config.ts\n\tconst configPath = join(dir, 'appfunnel.config.ts')\n\tif (existsSync(configPath)) {\n\t\tlet config = readFileSync(configPath, 'utf-8')\n\t\tconfig = config.replace('__PROJECT_ID__', projectId)\n\t\tconfig = config.replace('__NAME__', name)\n\n\t\t// If we have product bindings, replace the products section\n\t\tif (productBindings.length > 0) {\n\t\t\tconst itemsStr = productBindings\n\t\t\t\t.map((b) => {\n\t\t\t\t\tconst fields = [\n\t\t\t\t\t\t`\\t\\t\\t{ id: '${b.id}'`,\n\t\t\t\t\t\t`name: '${b.name}'`,\n\t\t\t\t\t\t`storePriceId: '${b.storePriceId}'`,\n\t\t\t\t\t]\n\t\t\t\t\tif (b.trialDays) fields.push(`trialDays: ${b.trialDays}`)\n\t\t\t\t\tif (b.trialStorePriceId)\n\t\t\t\t\t\tfields.push(`trialStorePriceId: '${b.trialStorePriceId}'`)\n\t\t\t\t\treturn fields.join(', ') + ' }'\n\t\t\t\t})\n\t\t\t\t.join(',\\n')\n\n\t\t\tconst defaultId = productBindings[0].id\n\t\t\tconfig = config.replace(\n\t\t\t\t/products:\\s*\\{[^}]*items:\\s*\\[[^\\]]*\\][^}]*\\}/s,\n\t\t\t\t`products: {\\n\\t\\titems: [\\n${itemsStr},\\n\\t\\t],\\n\\t\\tdefaultId: '${defaultId}',\\n\\t}`\n\t\t\t)\n\t\t}\n\n\t\twriteFileSync(configPath, config)\n\t}\n\n\t// 6. Generate package.json\n\tconst sdkVersion = `^${__CLI_VERSION__}`\n\n\twriteFileSync(\n\t\tjoin(dir, 'package.json'),\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tversion: '0.1.0',\n\t\t\t\tprivate: true,\n\t\t\t\ttype: 'module',\n\t\t\t\tscripts: {\n\t\t\t\t\tdev: 'appfunnel dev',\n\t\t\t\t\tbuild: 'appfunnel build',\n\t\t\t\t\tpublish: 'appfunnel publish',\n\t\t\t\t},\n\t\t\t\tdependencies: {\n\t\t\t\t\t'@appfunnel-dev/sdk': sdkVersion,\n\t\t\t\t\treact: '^18.3.0',\n\t\t\t\t\t'react-dom': '^18.3.0',\n\t\t\t\t},\n\t\t\t\tdevDependencies: {\n\t\t\t\t\tappfunnel: sdkVersion,\n\t\t\t\t\ttypescript: '^5.4.0',\n\t\t\t\t\t'@types/react': '^18.2.0',\n\t\t\t\t\t'@types/react-dom': '^18.2.0',\n\t\t\t\t\tvite: '^6.0.0',\n\t\t\t\t\t'@vitejs/plugin-react': '^4.0.0',\n\t\t\t\t\ttailwindcss: '^4.0.0',\n\t\t\t\t\t'@tailwindcss/vite': '^4.0.0',\n\t\t\t\t},\n\t\t\t},\n\t\t\tnull,\n\t\t\t2\n\t\t) + '\\n'\n\t)\n\n\ts.stop()\n\n\tconsole.log()\n\tlog.success(`Created ${pc.bold(name)} for project ${pc.bold(project.name)}`)\n\tconsole.log()\n\tconsole.log(` ${pc.dim('cd')} ${name}`)\n\tconsole.log(` ${pc.dim('npm install')}`)\n\tconsole.log(` ${pc.dim('appfunnel dev')}`)\n\tconsole.log()\n}\n","import { createServer } from 'node:http'\nimport { randomUUID } from 'node:crypto'\nimport open from 'open'\nimport * as log from '../lib/logger.js'\nimport { writeCredentials } from '../lib/auth.js'\n\nconst AUTH_BASE_URL = 'https://appfunnel.net'\nconst TIMEOUT_MS = 120_000 // 2 minutes\n\nexport async function loginCommand(): Promise<void> {\n\tconst state = randomUUID()\n\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst server = createServer((req, res) => {\n\t\t\tconst url = new URL(req.url || '/', `http://localhost`)\n\t\t\tif (url.pathname !== '/callback') {\n\t\t\t\tres.writeHead(404)\n\t\t\t\tres.end('Not found')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst token = url.searchParams.get('token')\n\t\t\tconst returnedState = url.searchParams.get('state')\n\t\t\tconst userId = url.searchParams.get('userId') || ''\n\t\t\tconst email = url.searchParams.get('email') || ''\n\t\t\tconst expiresAt = url.searchParams.get('expiresAt') || ''\n\n\t\t\tif (returnedState !== state) {\n\t\t\t\tres.writeHead(400)\n\t\t\t\tres.end('Invalid state parameter. Please try again.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (!token) {\n\t\t\t\tres.writeHead(400)\n\t\t\t\tres.end('No token received. Please try again.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Store credentials\n\t\t\twriteCredentials({ token, userId, email, expiresAt })\n\n\t\t\t// Send success page\n\t\t\tres.writeHead(200, { 'Content-Type': 'text/html' })\n\t\t\tres.end(`\n <!DOCTYPE html>\n <html>\n <body style=\"font-family: system-ui; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;\">\n <div style=\"text-align: center;\">\n <h1>Logged in!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </div>\n </body>\n </html>\n `)\n\n\t\t\t// Clean up\n\t\t\tspinner.stop()\n\t\t\tlog.success(`Logged in as ${email || userId}`)\n\t\t\tserver.close()\n\t\t\tresolve()\n\t\t})\n\n\t\t// Listen on random port\n\t\tserver.listen(0, '127.0.0.1', () => {\n\t\t\tconst addr = server.address()\n\t\t\tif (!addr || typeof addr === 'string') {\n\t\t\t\treject(new Error('Failed to start local server'))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst port = addr.port\n\t\t\tconst authUrl = `${AUTH_BASE_URL}/cli/authorize?port=${port}&state=${state}`\n\n\t\t\tlog.info('Opening browser for authentication...')\n\t\t\topen(authUrl).catch(() => {\n\t\t\t\tlog.warn(`Could not open browser. Please visit:\\n ${authUrl}`)\n\t\t\t})\n\t\t})\n\n\t\tconst spinner = log.spinner('Waiting for authentication...')\n\n\t\t// Timeout\n\t\tconst timeout = setTimeout(() => {\n\t\t\tspinner.stop()\n\t\t\tserver.close()\n\t\t\treject(new Error('Authentication timed out. Please try again.'))\n\t\t}, TIMEOUT_MS)\n\n\t\tserver.on('close', () => clearTimeout(timeout))\n\t})\n}\n","import pc from 'picocolors'\nimport { requireAuth } from '../lib/auth.js'\nimport { CLIError } from '../lib/errors.js'\nimport * as logger from '../lib/logger.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\nexport async function whoamiCommand(): Promise<void> {\n const creds = requireAuth()\n\n const spin = logger.spinner('Verifying credentials…')\n\n try {\n const response = await fetch(`${DEFAULT_API_BASE}/user`, {\n headers: {\n Authorization: creds.token,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n spin.stop()\n throw new CLIError(\n 'AUTH_EXPIRED',\n 'Token is no longer valid.',\n \"Run 'appfunnel login' to re-authenticate.\",\n )\n }\n\n const user = (await response.json()) as { email: string; id: string }\n spin.stop()\n\n logger.success(`Logged in as ${pc.bold(user.email)}`)\n logger.info(`User ID: ${pc.dim(user.id)}`)\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt)\n logger.info(`Token expires: ${pc.dim(expiresAt.toLocaleString())}`)\n }\n } catch (err) {\n spin.stop()\n if (err instanceof CLIError) throw err\n throw new CLIError(\n 'API_ERROR',\n 'Failed to reach the API. Check your internet connection.',\n )\n }\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { CLIError } from './errors.js'\n\nexport interface VariableConfig {\n type: string\n default?: unknown\n persist?: boolean\n}\n\nexport interface AppFunnelConfig {\n projectId: string\n name: string\n funnelId?: string\n initialPageKey: string\n defaultLocale?: string\n /** Response variables — stored as answers.* */\n responses?: Record<string, VariableConfig>\n /** Query param variables — stored as query.* */\n queryParams?: Record<string, VariableConfig>\n /** Data variables — stored as data.* */\n data?: Record<string, VariableConfig>\n products?: {\n items: Array<{ id: string; name: string; storePriceId: string; trialDays?: number; trialStorePriceId?: string }>\n defaultId?: string\n }\n integrations?: Record<string, Record<string, unknown>>\n pages?: Record<string, { name: string; type: string; slug?: string }>\n routes?: Record<string, Array<{ to: string; when?: unknown }>>\n}\n\nconst CONFIG_FILE = 'appfunnel.config.ts'\n\n/**\n * Load and evaluate the appfunnel.config.ts file using esbuild (a Vite dep).\n */\nexport async function loadConfig(cwd: string): Promise<AppFunnelConfig> {\n const configPath = join(cwd, CONFIG_FILE)\n\n if (!existsSync(configPath)) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n `No ${CONFIG_FILE} found in ${cwd}.`,\n \"Run 'appfunnel init' to create a new project, or cd into your project directory.\",\n )\n }\n\n // Use esbuild (already installed as a Vite dep) to transpile TS → JS\n const { transform } = await import('esbuild')\n const raw = readFileSync(configPath, 'utf-8')\n\n const result = await transform(raw, {\n loader: 'ts',\n format: 'esm',\n target: 'es2022',\n })\n\n // Evaluate the transpiled code\n // Strip the import of defineConfig since it's just a passthrough\n const code = result.code\n .replace(/import\\s*\\{[^}]*\\}\\s*from\\s*['\"]@appfunnel-dev\\/sdk['\"]\\s*;?/g, '')\n .replace(/\\bdefineConfig\\s*\\(/g, '(')\n\n // Use dynamic import via data URI\n const dataUri = `data:text/javascript;base64,${Buffer.from(code).toString('base64')}`\n const mod = await import(dataUri)\n const config = mod.default as AppFunnelConfig\n\n if (!config) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n `Invalid config in ${CONFIG_FILE}.`,\n 'Make sure your config exports a valid object with defineConfig().',\n )\n }\n\n return config\n}\n\n/**\n * Resolve the absolute path to the project's src directory.\n */\nexport function resolveSrcDir(cwd: string): string {\n return resolve(cwd, 'src')\n}\n\n/**\n * Resolve the absolute path to the pages directory.\n */\nexport function resolvePagesDir(cwd: string): string {\n return resolve(cwd, 'src', 'pages')\n}\n","import { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { CLIError } from './errors.js'\n\ninterface PackageJson {\n\tversion: string\n}\n\n/**\n * Check that CLI major.minor matches the installed @appfunnel-dev/sdk version.\n */\nexport function checkVersionCompatibility(cwd: string): void {\n\tconst cliVersion = __CLI_VERSION__\n\tconst sdkVersion = getSdkVersion(cwd)\n\n\tconst [cliMajor, cliMinor] = cliVersion.split('.').map(Number)\n\tconst [sdkMajor, sdkMinor] = sdkVersion.split('.').map(Number)\n\n\tif (cliMajor !== sdkMajor || cliMinor !== sdkMinor) {\n\t\tthrow new CLIError(\n\t\t\t'VERSION_MISMATCH',\n\t\t\t`CLI version ${cliVersion} requires @appfunnel-dev/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,\n\t\t\t\"Run 'npm install @appfunnel-dev/sdk@latest' to update.\"\n\t\t)\n\t}\n}\n\nfunction getSdkVersion(cwd: string): string {\n\ttry {\n\t\tconst pkgPath = join(\n\t\t\tcwd,\n\t\t\t'node_modules',\n\t\t\t'@appfunnel-dev',\n\t\t\t'sdk',\n\t\t\t'package.json'\n\t\t)\n\t\tconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as PackageJson\n\t\treturn pkg.version\n\t} catch {\n\t\tthrow new CLIError(\n\t\t\t'VERSION_MISMATCH',\n\t\t\t'@appfunnel-dev/sdk is not installed.',\n\t\t\t\"Run 'npm install @appfunnel-dev/sdk' to install it.\"\n\t\t)\n\t}\n}\n","import { readdirSync, readFileSync, existsSync } from 'node:fs'\nimport { join, basename } from 'node:path'\nimport { resolvePagesDir } from '../lib/config.js'\nimport { CLIError } from '../lib/errors.js'\nimport type ts from 'typescript'\n\nexport interface PageDefinition {\n name: string\n type?: string\n slug?: string\n routes?: Array<{ to: string; when?: unknown }>\n}\n\n/**\n * Scan src/pages/ for .tsx files and return page keys.\n */\nexport function scanPages(cwd: string): string[] {\n const pagesDir = resolvePagesDir(cwd)\n\n if (!existsSync(pagesDir)) {\n throw new CLIError(\n 'NO_PAGES',\n 'No src/pages/ directory found.',\n 'Create src/pages/ and add at least one .tsx page file.',\n )\n }\n\n const files = readdirSync(pagesDir)\n .filter((f) => f.endsWith('.tsx') && !f.startsWith('_'))\n .map((f) => basename(f, '.tsx'))\n .sort()\n\n if (files.length === 0) {\n throw new CLIError(\n 'NO_PAGES',\n 'No page files found in src/pages/.',\n 'Add .tsx files to src/pages/. Each file is a funnel page.',\n )\n }\n\n return files\n}\n\n/**\n * Extract definePage() metadata from each page file using the TypeScript compiler API.\n */\nexport async function extractPageDefinitions(\n cwd: string,\n pageKeys: string[],\n): Promise<Record<string, PageDefinition>> {\n const ts = await import('typescript') as typeof import('typescript')\n const pagesDir = resolvePagesDir(cwd)\n const result: Record<string, PageDefinition> = {}\n\n for (const key of pageKeys) {\n const filePath = join(pagesDir, `${key}.tsx`)\n const source = readFileSync(filePath, 'utf-8')\n\n const definition = extractDefinePage(ts, source, filePath)\n if (definition) {\n result[key] = definition\n } else {\n // Page without definePage() — use defaults\n result[key] = {\n name: key,\n type: 'default',\n }\n }\n }\n\n return result\n}\n\n/**\n * Parse a single page file and extract the definePage() argument.\n */\nfunction extractDefinePage(\n ts: typeof import('typescript'),\n source: string,\n fileName: string,\n): PageDefinition | null {\n const sourceFile = ts.createSourceFile(\n fileName,\n source,\n ts.ScriptTarget.Latest,\n true,\n ts.ScriptKind.TSX,\n )\n\n let definition: PageDefinition | null = null\n\n function visit(node: ts.Node): void {\n // Look for: export const page = definePage({ ... })\n if (ts.isVariableStatement(node)) {\n const isExported = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.ExportKeyword,\n )\n if (!isExported) return\n\n for (const decl of node.declarationList.declarations) {\n if (\n ts.isIdentifier(decl.name) &&\n decl.name.text === 'page' &&\n decl.initializer &&\n ts.isCallExpression(decl.initializer)\n ) {\n const call = decl.initializer\n const callee = call.expression\n\n // Check if callee is \"definePage\"\n if (ts.isIdentifier(callee) && callee.text === 'definePage') {\n const arg = call.arguments[0]\n if (arg && ts.isObjectLiteralExpression(arg)) {\n definition = extractObjectLiteral(ts, arg) as unknown as PageDefinition\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n ts.forEachChild(sourceFile, visit)\n return definition\n}\n\n/**\n * Recursively extract a TypeScript object literal into a plain JS object.\n */\nfunction extractObjectLiteral(\n ts: typeof import('typescript'),\n node: ts.ObjectLiteralExpression,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const prop of node.properties) {\n if (!ts.isPropertyAssignment(prop)) continue\n if (!ts.isIdentifier(prop.name) && !ts.isStringLiteral(prop.name)) continue\n\n const key = ts.isIdentifier(prop.name) ? prop.name.text : prop.name.text\n result[key] = extractValue(ts, prop.initializer)\n }\n\n return result\n}\n\n/**\n * Extract a static value from a TypeScript AST node.\n */\nfunction extractValue(\n ts: typeof import('typescript'),\n node: ts.Expression,\n): unknown {\n // String literal\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text\n }\n\n // Numeric literal\n if (ts.isNumericLiteral(node)) {\n return Number(node.text)\n }\n\n // Boolean / null / undefined\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false\n if (node.kind === ts.SyntaxKind.NullKeyword) return null\n if (node.kind === ts.SyntaxKind.UndefinedKeyword) return undefined\n\n // Array literal\n if (ts.isArrayLiteralExpression(node)) {\n return node.elements.map((el) => extractValue(ts, el))\n }\n\n // Object literal\n if (ts.isObjectLiteralExpression(node)) {\n return extractObjectLiteral(ts, node)\n }\n\n // Prefix unary (negative numbers)\n if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken) {\n const operand = extractValue(ts, node.operand)\n if (typeof operand === 'number') return -operand\n }\n\n // Can't statically evaluate — return undefined\n return undefined\n}\n","import { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\n\ninterface EntryOptions {\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n pagesDir: string\n funnelTsxPath: string\n isDev: boolean\n priceData?: Map<string, unknown>\n translations?: Record<string, Record<string, string>>\n}\n\n/**\n * Generate the virtual entry module source code.\n *\n * This creates a mini SPA that:\n * - Mounts FunnelProvider once\n * - Wraps with the user's funnel.tsx\n * - Client-side routes between pages via the SDK's Router\n * - Lazy-loads page components\n */\nexport function generateEntrySource(options: EntryOptions): string {\n const { config, pages, pagesDir, funnelTsxPath, isDev, translations } = options\n const pageKeys = Object.keys(pages)\n\n // Merge definePage() metadata into config\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Override config pages/routes with extracted ones\n const fullConfig = {\n ...config,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n }\n\n // Generate lazy imports for each page\n const pageImports = pageKeys\n .map(\n (key) =>\n ` '${key}': lazy(() => import('${join(pagesDir, key + '.tsx').replace(/\\\\/g, '/')}')),`,\n )\n .join('\\n')\n\n // Build slug → key mapping\n const slugMap: Record<string, string> = {}\n for (const [key, def] of Object.entries(pages)) {\n slugMap[def.slug || key] = key\n }\n\n // Serialize price data as a Map constructor call\n // In production, runtime data (prices, integrations, etc.) is injected via window.__APPFUNNEL_DATA__\n const priceDataCode = isDev\n ? (options.priceData && options.priceData.size > 0\n ? `const priceData = new Map(${JSON.stringify([...options.priceData.entries()])});`\n : `const priceData = undefined;`)\n : `const priceData = (() => {\n const rd = typeof window !== 'undefined' && window.__APPFUNNEL_DATA__;\n if (!rd || !rd.products?.items) return undefined;\n // Build price map from server-injected product data\n const map = new Map();\n for (const item of rd.products.items) {\n if (item.priceData && item.storePriceId) map.set(item.storePriceId, item.priceData);\n if (item.trialPriceData && item.trialStorePriceId) map.set(item.trialStorePriceId, item.trialPriceData);\n }\n return map.size > 0 ? map : undefined;\n})();`\n\n const trackingCode = isDev\n ? `\n// Dev mode: mock tracking — log events to console\nglobalThis.__APPFUNNEL_DEV__ = true;\n`\n : ''\n\n // Import app.css if it exists (Tailwind, global styles, etc.)\n const appCssPath = join(pagesDir, '..', 'app.css').replace(/\\\\/g, '/')\n const hasAppCss = existsSync(join(pagesDir, '..', 'app.css'))\n\n return `\nimport { StrictMode, Component, lazy, Suspense, useState, useCallback, useEffect, useTransition, useDeferredValue, useSyncExternalStore } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { FunnelProvider, useNavigation } from '@appfunnel-dev/sdk'\n${hasAppCss ? `import '${appCssPath}'` : ''}\nimport FunnelWrapper from '${funnelTsxPath.replace(/\\\\/g, '/')}'\n\n${trackingCode}\n\nconst pageComponents = {\n${pageImports}\n}\n\n${priceDataCode}\n\nconst translations = ${translations ? JSON.stringify(translations) : 'undefined'}\n\nconst config = ${JSON.stringify(fullConfig, null, 2)}\n\nconst keyToSlug = ${JSON.stringify(\n Object.fromEntries(Object.entries(slugMap).map(([s, k]) => [k, s])),\n )}\nconst slugToKey = ${JSON.stringify(slugMap)}\n\nconst DEV_CAMPAIGN_SLUG = 'campaign'\nconst DEFAULT_INITIAL = '${config.initialPageKey}'\n\n/**\n * Parse the URL to extract basePath, campaignSlug, and initial page.\n *\n * URL pattern: /f/<campaignSlug>[/<pageSlug>]\n *\n * In dev, redirects bare / to /f/<projectId> so the URL matches production.\n */\nfunction parseUrl() {\n const parts = window.location.pathname.split('/').filter(Boolean)\n\n // /f/<campaignSlug>[/<pageSlug>]\n if (parts[0] === 'f' && parts.length >= 2) {\n const campaignSlug = parts[1]\n const pageSlug = parts[2] || ''\n const pageKey = pageSlug ? (slugToKey[pageSlug] || '') : ''\n return {\n basePath: '/f/' + campaignSlug,\n campaignSlug,\n initialPage: pageKey || DEFAULT_INITIAL,\n }\n }\n\n // Bare URL → redirect to /f/<slug> in dev\n ${isDev ? `\n window.history.replaceState(null, '', '/f/' + DEV_CAMPAIGN_SLUG)\n return {\n basePath: '/f/' + DEV_CAMPAIGN_SLUG,\n campaignSlug: DEV_CAMPAIGN_SLUG,\n initialPage: DEFAULT_INITIAL,\n }` : `\n return {\n basePath: '',\n campaignSlug: '',\n initialPage: DEFAULT_INITIAL,\n }`}\n}\n\nconst { basePath, campaignSlug, initialPage } = parseUrl()\n\n${isDev ? `\nclass ErrorBoundary extends Component {\n constructor(props) {\n super(props)\n this.state = { error: null }\n }\n static getDerivedStateFromError(error) {\n return { error }\n }\n componentDidCatch(error, info) {\n console.error('[AppFunnel] Render error:', error, info)\n }\n render() {\n if (this.state.error) {\n return (\n <div style={{ padding: '2rem', fontFamily: 'monospace' }}>\n <h2 style={{ color: 'red' }}>AppFunnel Error</h2>\n <pre style={{ whiteSpace: 'pre-wrap', color: '#333' }}>{this.state.error.message}</pre>\n <pre style={{ whiteSpace: 'pre-wrap', color: '#666', fontSize: '12px' }}>{this.state.error.stack}</pre>\n </div>\n )\n }\n return this.props.children\n }\n}\n` : ''}\n\n/**\n * PageRenderer lives inside FunnelProvider so it can use SDK hooks.\n * Subscribes to the router — re-renders when the page changes.\n * Uses useTransition to keep showing the current page while the next one loads.\n */\nfunction PageRenderer() {\n const { currentPage, goToPage } = useNavigation()\n const routerPageKey = currentPage?.key || ''\n\n // Track the displayed page separately so we can transition smoothly\n const [displayedKey, setDisplayedKey] = useState(routerPageKey)\n const [isPending, startTransition] = useTransition()\n\n // When the router's page changes, transition to the new page\n useEffect(() => {\n if (routerPageKey && routerPageKey !== displayedKey) {\n startTransition(() => {\n setDisplayedKey(routerPageKey)\n })\n }\n }, [routerPageKey, displayedKey])\n\n // Sync URL with current page\n const slug = currentPage?.slug || routerPageKey\n useEffect(() => {\n const expectedPath = basePath ? basePath + '/' + slug : '/' + slug\n if (slug && window.location.pathname !== expectedPath) {\n window.history.pushState(null, '', expectedPath)\n }\n }, [slug])\n\n // Handle browser back/forward\n useEffect(() => {\n const handlePopState = () => {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n const key = slugToKey[path]\n if (key && key !== routerPageKey) {\n goToPage(key)\n }\n }\n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [routerPageKey, goToPage])\n\n const PageComponent = pageComponents[displayedKey]\n\n if (!PageComponent) {\n return <div style={{ padding: '2rem', color: 'red' }}>Page not found: {displayedKey}</div>\n }\n\n return (\n <Suspense fallback={null}>\n <PageComponent />\n </Suspense>\n )\n}\n\n// Runtime data injected by the server (production only)\nconst __rd = typeof window !== 'undefined' && window.__APPFUNNEL_DATA__\n\nfunction App() {\n // In production, merge server-injected integrations into config\n const runtimeConfig = __rd && __rd.integrations\n ? { ...config, integrations: { ...config.integrations, ...__rd.integrations } }\n : config\n\n const sessionData = __rd ? {\n campaignId: __rd.campaignId || '',\n funnelId: __rd.funnelId || config.funnelId || '',\n experimentId: __rd.experimentId || null,\n } : undefined\n\n return (\n <FunnelProvider\n config={runtimeConfig}\n initialPage={initialPage}\n basePath={basePath}\n campaignSlug={campaignSlug}\n priceData={priceData}\n sessionData={sessionData}\n translations={translations}\n >\n <FunnelWrapper>\n <PageRenderer />\n </FunnelWrapper>\n </FunnelProvider>\n )\n}\n\ncreateRoot(document.getElementById('root')).render(\n <StrictMode>\n ${isDev ? '<ErrorBoundary>' : ''}\n <App />\n ${isDev ? '</ErrorBoundary>' : ''}\n </StrictMode>\n)\n\n// Reveal body (the host page may set opacity:0 for a loading transition)\ndocument.body.style.opacity = '1'\n`\n}\n","/**\n * Generate the index.html template for the dev server and production build.\n */\nexport function generateHtml(title: string = 'AppFunnel'): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${title}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/@appfunnel/entry\"></script>\n </body>\n</html>`\n}\n","import { resolve, join } from 'node:path'\nimport { existsSync, writeFileSync, mkdirSync, readFileSync, readdirSync } from 'node:fs'\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\nimport { generateEntrySource } from './entry.js'\nimport { generateHtml } from './html.js'\n\nconst VIRTUAL_ENTRY_ID = '@appfunnel/entry'\nconst RESOLVED_VIRTUAL_ENTRY_ID = '\\0' + VIRTUAL_ENTRY_ID + '.tsx'\n\n/** Working directory for dev/build artifacts (like .next/) */\nconst APPFUNNEL_DIR = '.appfunnel'\n\ninterface PluginOptions {\n cwd: string\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n isDev: boolean\n priceData?: Map<string, unknown>\n onPagesChange?: () => Promise<void>\n}\n\n/**\n * Load all locale JSON files from <cwd>/locales/.\n * Returns a TranslationMap: { \"en\": { \"key\": \"value\" }, \"de\": { ... } }\n */\nfunction loadTranslations(cwd: string): Record<string, Record<string, string>> | undefined {\n const localesDir = join(cwd, 'locales')\n if (!existsSync(localesDir)) return undefined\n\n const translations: Record<string, Record<string, string>> = {}\n let hasAny = false\n\n for (const file of readdirSync(localesDir)) {\n if (!file.endsWith('.json')) continue\n const locale = file.replace(/\\.json$/, '')\n try {\n const content = readFileSync(join(localesDir, file), 'utf-8')\n translations[locale] = JSON.parse(content)\n hasAny = true\n } catch {\n // Skip invalid JSON files\n }\n }\n\n return hasAny ? translations : undefined\n}\n\nexport function appfunnelPlugin(options: PluginOptions): Plugin {\n const { cwd, config, isDev } = options\n let pages = options.pages\n const pagesDir = resolve(cwd, 'src', 'pages')\n const funnelTsxPath = resolve(cwd, 'src', 'funnel.tsx')\n const appfunnelDir = join(cwd, APPFUNNEL_DIR)\n const htmlPath = join(appfunnelDir, 'index.html')\n const localesDir = join(cwd, 'locales')\n\n function getEntrySource(): string {\n return generateEntrySource({\n config,\n pages,\n pagesDir,\n funnelTsxPath,\n isDev,\n priceData: options.priceData,\n translations: loadTranslations(cwd),\n })\n }\n\n return {\n name: 'appfunnel',\n\n config() {\n // Ensure .appfunnel/ exists and write the HTML shell\n mkdirSync(appfunnelDir, { recursive: true })\n writeFileSync(htmlPath, generateHtml(config.name || 'AppFunnel'))\n\n return {\n // Don't let Vite auto-serve index.html — we handle it ourselves\n appType: 'custom',\n resolve: {\n alias: {\n '@': resolve(cwd, 'src'),\n },\n dedupe: ['react', 'react-dom'],\n },\n esbuild: {\n jsx: 'automatic',\n },\n optimizeDeps: {\n include: ['react', 'react-dom', 'react/jsx-runtime'],\n force: true,\n },\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_ID || id === '/' + VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n return null\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n const { transform } = await import('esbuild')\n const source = getEntrySource()\n const result = await transform(source, {\n loader: 'tsx',\n jsx: 'automatic',\n sourcefile: 'appfunnel-entry.tsx',\n })\n return result.code\n }\n return null\n },\n\n configureServer(devServer) {\n // Watch for page file additions/removals\n const watcher = devServer.watcher\n watcher.add(pagesDir)\n\n const handlePagesChange = async () => {\n if (options.onPagesChange) {\n await options.onPagesChange()\n }\n const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ENTRY_ID)\n if (mod) {\n devServer.moduleGraph.invalidateModule(mod)\n }\n devServer.ws.send({ type: 'full-reload' })\n }\n\n watcher.on('add', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n watcher.on('unlink', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n // Watch appfunnel.config.ts for changes → full reload\n const configPath = join(cwd, 'appfunnel.config.ts')\n if (existsSync(configPath)) {\n watcher.add(configPath)\n watcher.on('change', (file) => {\n if (file === configPath) {\n devServer.ws.send({ type: 'full-reload' })\n }\n })\n }\n\n // Watch locales/ for changes → full reload\n if (existsSync(localesDir)) {\n watcher.add(localesDir)\n watcher.on('change', (file) => {\n if (file.startsWith(localesDir) && file.endsWith('.json')) {\n const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ENTRY_ID)\n if (mod) {\n devServer.moduleGraph.invalidateModule(mod)\n }\n devServer.ws.send({ type: 'full-reload' })\n }\n })\n }\n\n // Since appType is 'custom', we serve HTML ourselves.\n // Registered after Vite internals so /@vite, /node_modules etc. resolve first.\n return () => {\n devServer.middlewares.use(async (req, res, next) => {\n const url = req.url?.split('?')[0] || ''\n\n // Let Vite handle static assets and internal routes\n if (url.includes('.') || url.startsWith('/@') || url.startsWith('/node_modules')) {\n return next()\n }\n\n try {\n const rawHtml = readFileSync(htmlPath, 'utf-8')\n const html = await devServer.transformIndexHtml(req.url || '/', rawHtml)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html')\n res.end(html)\n } catch (err) {\n next(err)\n }\n })\n }\n },\n\n transformIndexHtml(html) {\n return html\n },\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, resolvePagesDir } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { promptForProject } from '../lib/projects.js'\nimport { fetchPrices } from '../lib/api.js'\n\nexport async function devCommand(options: { port?: number }): Promise<void> {\n const cwd = process.cwd()\n const port = options.port || 5173\n\n // 1. Auth check\n const creds = requireAuth()\n\n // 2. Version check\n checkVersionCompatibility(cwd)\n\n // 3. Load config\n const s = log.spinner('Loading config...')\n const config = await loadConfig(cwd)\n s.stop()\n\n // 4. If no projectId, prompt for one and update the config file\n if (!config.projectId) {\n log.info('No projectId found in appfunnel.config.ts')\n const projectId = await promptForProject(creds.token)\n config.projectId = projectId\n\n // Write projectId back to the config file\n const configPath = join(cwd, 'appfunnel.config.ts')\n const configSource = readFileSync(configPath, 'utf-8')\n let updated: string\n\n if (/projectId:\\s*['\"]/.test(configSource)) {\n // Replace existing projectId value\n updated = configSource.replace(\n /projectId:\\s*['\"].*?['\"]/,\n `projectId: '${projectId}'`,\n )\n } else {\n // Insert projectId after the opening of defineConfig({\n updated = configSource.replace(\n /(defineConfig\\(\\{[\\t ]*\\n)/,\n `$1\\tprojectId: '${projectId}',\\n`,\n )\n }\n\n if (updated !== configSource) {\n writeFileSync(configPath, updated)\n log.success(`Updated projectId in appfunnel.config.ts`)\n } else {\n log.warn(`Could not auto-update appfunnel.config.ts — add projectId: '${projectId}' manually.`)\n }\n }\n\n // 5. Scan and extract pages\n const s2 = log.spinner('Scanning pages...')\n let pageKeys = scanPages(cwd)\n let pages = await extractPageDefinitions(cwd, pageKeys)\n s2.stop()\n\n log.info(`Found ${pageKeys.length} pages: ${pageKeys.join(', ')}`)\n\n // 6. Fetch store prices (cached for dev session)\n let priceData: Map<string, unknown> = new Map()\n if (config.projectId && config.products?.items?.length) {\n try {\n const storePriceIds = [\n ...new Set(\n config.products.items.flatMap((item) =>\n [item.storePriceId, item.trialStorePriceId].filter(Boolean) as string[]\n )\n ),\n ]\n\n log.info(`Fetching ${storePriceIds.length} store prices: ${storePriceIds.join(', ')}`)\n\n const s3 = log.spinner('Fetching store prices...')\n priceData = await fetchPrices(config.projectId, storePriceIds, { token: creds.token })\n s3.stop()\n\n // Check that every requested price was returned\n const missingIds = storePriceIds.filter((id) => !priceData.has(id))\n if (missingIds.length > 0) {\n log.error(`Missing store prices: ${missingIds.join(', ')}`)\n log.error('Make sure these storePriceId values in your config match prices in your project.')\n process.exit(1)\n }\n\n log.success(`Fetched ${priceData.size}/${storePriceIds.length} store prices`)\n } catch (err) {\n log.error(`Failed to fetch store prices: ${(err as Error).message}`)\n process.exit(1)\n }\n }\n\n // 7. Start Vite dev server\n const { createServer } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n // Load @tailwindcss/vite from the user's project\n let tailwindPlugin: any = null\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(join(cwd, 'package.json'))\n const tailwindPath = require.resolve('@tailwindcss/vite')\n const tailwindVite = await import(tailwindPath)\n tailwindPlugin = tailwindVite.default\n } catch {\n // Not installed — skip\n }\n\n const server = await createServer({\n root: cwd,\n server: {\n port,\n strictPort: false,\n },\n plugins: [\n react.default(),\n ...(tailwindPlugin ? [tailwindPlugin()] : []),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: true,\n priceData,\n async onPagesChange() {\n // Re-scan pages when files are added/removed\n pageKeys = scanPages(cwd)\n pages = await extractPageDefinitions(cwd, pageKeys)\n log.info(`Pages updated: ${pageKeys.join(', ')}`)\n },\n }),\n ],\n css: {\n postcss: cwd,\n },\n })\n\n await server.listen()\n\n const address = server.resolvedUrls?.local?.[0] || `http://localhost:${port}`\n\n console.log()\n console.log(` ${pc.bold(config.name || 'AppFunnel')} dev server`)\n console.log()\n console.log(` ${pc.dim('Local:')} ${pc.cyan(address)}`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Tracking:')} ${pc.yellow('mocked (console)')}`)\n console.log()\n console.log(` ${pc.dim('Press')} ${pc.bold('Ctrl+C')} ${pc.dim('to stop')}`)\n console.log()\n}\n","import { resolve, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, type AppFunnelConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { generateHtml } from '../vite/html.js'\nimport { formatWarning } from '../lib/errors.js'\nimport { CLIError } from '../lib/errors.js'\n\nconst MAX_TOTAL_SIZE = 2 * 1024 * 1024 // 2MB\nconst MAX_PAGE_SIZE = 500 * 1024 // 500KB\n\n/** UTM query params — always included, no config needed */\nconst BUILTIN_QUERY_PARAMS: Record<string, { type: string }> = {\n utm_source: { type: 'string' },\n utm_medium: { type: 'string' },\n utm_campaign: { type: 'string' },\n utm_content: { type: 'string' },\n utm_term: { type: 'string' },\n}\n\nexport async function buildCommand(): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config + pages\n const s = log.spinner('Analyzing pages...')\n const config = await loadConfig(cwd)\n\n if (!config.projectId) {\n s.stop()\n throw new CLIError(\n 'MISSING_PROJECT_ID',\n 'Missing projectId in appfunnel.config.ts.',\n \"Run 'appfunnel dev' first to select a project, or add projectId manually.\",\n )\n }\n\n if (!config.initialPageKey) {\n s.stop()\n throw new CLIError(\n 'MISSING_INITIAL_PAGE_KEY',\n 'Missing initialPageKey in appfunnel.config.ts.',\n \"Set initialPageKey to the page key (filename without .tsx) of your first page.\",\n )\n }\n\n const pageKeys = scanPages(cwd)\n const pages = await extractPageDefinitions(cwd, pageKeys)\n s.stop()\n\n // 3. Validate routes\n validateRoutes(config, pages, pageKeys)\n\n log.info(`Building ${pageKeys.length} pages...`)\n\n // 4. Build with Vite\n const outDir = resolve(cwd, 'dist')\n const { build } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n // Try to load @tailwindcss/vite from the user's project\n let tailwindPlugin: any = null\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(join(cwd, 'package.json'))\n const tailwindPath = require.resolve('@tailwindcss/vite')\n const tailwindVite = await import(tailwindPath)\n tailwindPlugin = tailwindVite.default\n } catch {\n // Not installed in the user's project — skip\n }\n\n // Write index.html for Vite to use as entry\n const htmlPath = resolve(cwd, 'index.html')\n const htmlContent = generateHtml(config.name || 'AppFunnel')\n writeFileSync(htmlPath, htmlContent)\n\n try {\n await build({\n root: cwd,\n base: './',\n build: {\n outDir,\n emptyOutDir: true,\n sourcemap: false,\n minify: 'esbuild',\n rollupOptions: {\n output: {\n manualChunks(id) {\n if (id.includes('node_modules/react')) {\n return 'vendor-react'\n }\n if (id.includes('@appfunnel-dev/sdk')) {\n return 'vendor-sdk'\n }\n },\n },\n },\n },\n plugins: [\n react.default(),\n ...(tailwindPlugin ? [tailwindPlugin()] : []),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: false,\n }),\n ],\n css: {\n postcss: cwd,\n },\n logLevel: 'warn',\n })\n } finally {\n // Clean up the temporary index.html\n try {\n const { unlinkSync } = await import('node:fs')\n unlinkSync(htmlPath)\n } catch { /* ignore */ }\n }\n\n // 5. Generate manifest\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Collect asset info\n const assets = collectAssets(outDir)\n const totalSize = assets.reduce((sum, a) => sum + a.size, 0)\n\n const manifest = {\n version: 1,\n buildHash: randomUUID(),\n sdkVersion: getSdkVersion(cwd),\n projectId: config.projectId,\n funnelId: config.funnelId,\n name: config.name,\n initialPageKey: config.initialPageKey,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n responses: config.responses || {},\n queryParams: { ...BUILTIN_QUERY_PARAMS, ...config.queryParams },\n data: config.data || {},\n products: config.products || {},\n defaultLocale: config.defaultLocale,\n assets,\n totalSize,\n }\n\n writeFileSync(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n')\n\n // 6. Print report\n console.log()\n log.success('Build complete')\n console.log()\n console.log(` ${pc.dim('Output:')} dist/`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Size:')} ${formatSize(totalSize)}`)\n console.log()\n\n // Print per-asset sizes\n for (const asset of assets) {\n const sizeStr = formatSize(asset.size)\n const isOver = asset.size > MAX_PAGE_SIZE\n console.log(` ${isOver ? pc.yellow('!') : pc.dim('·')} ${pc.dim(asset.path)} ${isOver ? pc.yellow(sizeStr) : pc.dim(sizeStr)}`)\n }\n console.log()\n\n // Warn on size limits\n if (totalSize > MAX_TOTAL_SIZE) {\n console.log(formatWarning(\n 'BUNDLE_TOO_LARGE',\n `Total bundle size (${formatSize(totalSize)}) exceeds the 2MB limit.`,\n 'This will be rejected on publish. Reduce dependencies or code-split.',\n ))\n console.log()\n }\n\n for (const asset of assets) {\n if (asset.size > MAX_PAGE_SIZE && asset.path.endsWith('.js')) {\n console.log(formatWarning(\n 'PAGE_SIZE',\n `${asset.path} is ${formatSize(asset.size)} (limit: 500KB).`,\n 'Consider reducing dependencies in this page.',\n ))\n }\n }\n}\n\nfunction validateRoutes(\n config: AppFunnelConfig,\n pages: Record<string, { routes?: Array<{ to: string; when?: unknown }> }>,\n pageKeys: string[],\n): void {\n const allPageKeys = new Set(pageKeys)\n\n // Build full set of known variables from all namespaced sections\n const allVariables = new Set<string>()\n if (config.responses) {\n for (const key of Object.keys(config.responses)) {\n allVariables.add(`answers.${key}`)\n }\n }\n if (config.queryParams) {\n for (const key of Object.keys(config.queryParams)) {\n allVariables.add(`query.${key}`)\n }\n }\n if (config.data) {\n for (const key of Object.keys(config.data)) {\n allVariables.add(`data.${key}`)\n }\n }\n\n // Check routes from definePage()\n for (const [pageKey, def] of Object.entries(pages)) {\n if (!def.routes) continue\n for (const route of def.routes) {\n if (!allPageKeys.has(route.to)) {\n throw new CLIError(\n 'INVALID_ROUTE',\n `Page \"${pageKey}\" routes to \"${route.to}\" which does not exist.`,\n `Available pages: ${pageKeys.join(', ')}. Check src/pages/${pageKey}.tsx.`,\n )\n }\n\n // Validate condition variable references\n if (route.when) {\n validateConditionVariables(route.when, pageKey, allVariables)\n }\n }\n }\n}\n\nfunction validateConditionVariables(\n condition: unknown,\n pageKey: string,\n allVariables: Set<string>,\n): void {\n if (!condition || typeof condition !== 'object') return\n\n const cond = condition as Record<string, unknown>\n\n // Simple condition\n if (cond.variable && typeof cond.variable === 'string') {\n // Skip system variables (page.*, device.*, etc.) and user.*\n const prefix = cond.variable.split('.')[0]\n const systemPrefixes = ['page', 'device', 'browser', 'os', 'session', 'system', 'metadata', 'user', 'products', 'card', 'payment', 'stripe', 'subscription']\n if (!systemPrefixes.includes(prefix) && !allVariables.has(cond.variable)) {\n // Suggest the right config section based on the prefix\n const varName = cond.variable.includes('.') ? cond.variable.split('.').slice(1).join('.') : cond.variable\n let hint: string\n if (prefix === 'answers') {\n hint = `Add it to responses in appfunnel.config.ts: responses: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'query') {\n hint = `Add it to queryParams in appfunnel.config.ts: queryParams: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'data') {\n hint = `Add it to data in appfunnel.config.ts: data: { '${varName}': { type: 'string' } }`\n } else {\n hint = `Add it to the appropriate section (responses, queryParams, or data) in appfunnel.config.ts.`\n }\n throw new CLIError(\n 'UNDEFINED_VARIABLE',\n `Route condition in \"${pageKey}\" references variable \"${cond.variable}\" which is not defined.`,\n hint,\n )\n }\n }\n\n // Condition group\n if (Array.isArray(cond.rules)) {\n for (const rule of cond.rules) {\n validateConditionVariables(rule, pageKey, allVariables)\n }\n }\n}\n\nfunction collectAssets(outDir: string): Array<{ path: string; size: number }> {\n const assets: Array<{ path: string; size: number }> = []\n\n function walk(dir: string, prefix: string = ''): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n walk(fullPath, relPath)\n } else if (entry.name !== 'manifest.json' && !entry.name.startsWith('.')) {\n assets.push({ path: relPath, size: statSync(fullPath).size })\n }\n }\n }\n\n walk(outDir)\n return assets\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(2)}MB`\n}\n\nfunction getSdkVersion(cwd: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(cwd, 'node_modules', '@appfunnel-dev', 'sdk', 'package.json'), 'utf-8'))\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n","import { join } from 'node:path'\nimport { readFileSync, writeFileSync } from 'node:fs'\n\n/**\n * Patch appfunnel.config.ts to add a funnelId after the projectId line.\n * Uses simple string replacement — no AST parsing needed.\n */\nexport function patchConfigFunnelId(cwd: string, funnelId: string): void {\n const configPath = join(cwd, 'appfunnel.config.ts')\n let content = readFileSync(configPath, 'utf-8')\n\n // Already has funnelId — don't double-add\n if (content.includes('funnelId')) return\n\n // Insert funnelId after the projectId line\n const patched = content.replace(\n /(projectId:\\s*['\"][^'\"]+['\"],?\\s*\\n)/,\n `$1 funnelId: '${funnelId}',\\n`,\n )\n\n if (patched !== content) {\n writeFileSync(configPath, patched, 'utf-8')\n }\n}\n","import { resolve, join } from 'node:path'\nimport { readFileSync, existsSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { publishBuild } from '../lib/api.js'\nimport { CLIError } from '../lib/errors.js'\nimport { patchConfigFunnelId } from '../lib/config-patch.js'\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.html': 'text/html',\n '.json': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n}\n\nfunction getMimeType(path: string): string {\n const ext = path.substring(path.lastIndexOf('.'))\n return MIME_TYPES[ext] || 'application/octet-stream'\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(2)}MB`\n}\n\nexport async function publishCommand(options?: { promote?: boolean }): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n const creds = requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config\n const config = await loadConfig(cwd)\n\n const projectId = config.projectId\n if (!projectId) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No projectId in appfunnel.config.ts.',\n 'Add projectId to your config. You can find it in the dashboard.',\n )\n }\n\n // 3. Check build output exists\n const outDir = resolve(cwd, 'dist')\n const manifestPath = join(outDir, 'manifest.json')\n\n if (!existsSync(manifestPath)) {\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n 'No build output found.',\n \"Run 'appfunnel build' first.\",\n )\n }\n\n // 4. Read manifest\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'))\n const assets: Array<{ path: string; size: number }> = manifest.assets || []\n\n // 5. Read all asset files\n const s = log.spinner('Preparing assets...')\n const assetPayloads: Array<{ path: string; content: Buffer; contentType: string }> = []\n let totalBytes = 0\n\n for (let i = 0; i < assets.length; i++) {\n const asset = assets[i]\n const fullPath = join(outDir, asset.path)\n if (!existsSync(fullPath)) {\n s.stop()\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n `Build asset missing: ${asset.path}`,\n \"Run 'appfunnel build' to regenerate.\",\n )\n }\n const content = readFileSync(fullPath)\n totalBytes += content.length\n assetPayloads.push({\n path: asset.path,\n content,\n contentType: getMimeType(asset.path),\n })\n s.text = `Preparing assets... ${i + 1}/${assets.length} ${pc.dim(`(${formatSize(totalBytes)})`)}`\n }\n\n // 6. Upload\n s.text = `Uploading ${assets.length} assets ${pc.dim(`(${formatSize(totalBytes)})`)}`\n\n const result = await publishBuild(\n projectId,\n config.funnelId || '',\n manifest,\n assetPayloads,\n { token: creds.token },\n options?.promote,\n )\n\n s.stop()\n\n // 7. If the server created a new funnel, write funnelId back to config\n if (result.created && result.funnelId) {\n patchConfigFunnelId(cwd, result.funnelId)\n log.info(`Funnel created — funnelId added to appfunnel.config.ts`)\n }\n\n // 8. Print result\n console.log()\n log.success(result.activated ? 'Published and activated' : 'Published successfully')\n console.log()\n console.log(` ${pc.dim('Build ID:')} ${result.buildId}`)\n if (result.funnelId && !config.funnelId) {\n console.log(` ${pc.dim('Funnel:')} ${result.funnelId}`)\n }\n console.log(` ${pc.dim('Dashboard:')} ${pc.cyan(result.dashboardUrl)}`)\n console.log(` ${pc.dim('Assets:')} ${assets.length} files ${pc.dim(`(${formatSize(totalBytes)})`)}`)\n if (!result.activated) {\n console.log()\n console.log(` ${pc.dim('Tip:')} Use ${pc.cyan('--promote')} to activate immediately, or promote from the dashboard.`)\n }\n console.log()\n}\n","import { Command } from 'commander'\nimport pc from 'picocolors'\nimport { CLIError, formatError } from './lib/errors.js'\n\nconst program = new Command()\n\nprogram\n .name('appfunnel')\n .description('Build and publish headless AppFunnel projects')\n .version(__CLI_VERSION__)\n\nprogram\n .command('init')\n .argument('[name]', 'Project directory name')\n .description('Create a new AppFunnel project')\n .action(async (name?: string) => {\n const { initCommand } = await import('./commands/init.js')\n await initCommand(name)\n })\n\nprogram\n .command('login')\n .description('Authenticate with AppFunnel')\n .action(async () => {\n const { loginCommand } = await import('./commands/login.js')\n await loginCommand()\n })\n\nprogram\n .command('whoami')\n .description('Show the currently authenticated user')\n .action(async () => {\n const { whoamiCommand } = await import('./commands/whoami.js')\n await whoamiCommand()\n })\n\nprogram\n .command('dev')\n .description('Start the development server')\n .option('-p, --port <port>', 'Port number', '5173')\n .action(async (options: { port: string }) => {\n const { devCommand } = await import('./commands/dev.js')\n await devCommand({ port: parseInt(options.port, 10) })\n })\n\nprogram\n .command('build')\n .description('Build the funnel for production')\n .action(async () => {\n const { buildCommand } = await import('./commands/build.js')\n await buildCommand()\n })\n\nprogram\n .command('publish')\n .description('Publish the build to AppFunnel')\n .option('--promote', 'Activate the build immediately after publishing')\n .action(async (options: { promote?: boolean }) => {\n const { publishCommand } = await import('./commands/publish.js')\n await publishCommand({ promote: options.promote })\n })\n\n// Global error handler\nprogram.hook('postAction', () => {})\n\nasync function main() {\n try {\n await program.parseAsync(process.argv)\n } catch (err) {\n if (err instanceof CLIError) {\n console.error(formatError(err))\n process.exit(1)\n }\n // Unknown error\n console.error(`${pc.red('ERROR')}: ${err instanceof Error ? err.message : String(err)}`)\n if (err instanceof Error && err.stack) {\n console.error(pc.dim(err.stack))\n }\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":["pc","pc","DEFAULT_API_BASE","error","readFileSync","writeFileSync","join","pc","select","s","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readdirSync","readFileSync","existsSync","join","join","existsSync","resolve","join","existsSync","writeFileSync","mkdirSync","readFileSync","readdirSync","readFileSync","writeFileSync","join","pc","createServer","require","resolve","join","randomUUID","readFileSync","writeFileSync","readdirSync","pc","require","getSdkVersion","join","readFileSync","writeFileSync","resolve","join","readFileSync","existsSync","pc","formatSize","pc","initCommand","loginCommand","whoamiCommand","devCommand","buildCommand","publishCommand"]}
1
+ {"version":3,"sources":["../src/lib/errors.ts","../src/lib/logger.ts","../src/lib/auth.ts","../src/lib/projects.ts","../src/lib/api.ts","../src/commands/init.ts","../src/commands/login.ts","../src/commands/whoami.ts","../src/lib/config.ts","../src/lib/version.ts","../src/extract/pages.ts","../src/vite/entry.ts","../src/vite/html.ts","../src/vite/plugin.ts","../src/commands/dev.ts","../src/lib/computeFlow.ts","../src/commands/routes.ts","../src/commands/build.ts","../src/lib/config-patch.ts","../src/commands/publish.ts","../src/index.ts"],"sourcesContent":["import pc from 'picocolors'\n\nexport type ErrorCode =\n\t| 'AUTH_REQUIRED'\n\t| 'AUTH_EXPIRED'\n\t| 'CONFIG_NOT_FOUND'\n\t| 'INVALID_ROUTE'\n\t| 'UNDEFINED_VARIABLE'\n\t| 'VERSION_MISMATCH'\n\t| 'BUILD_NOT_FOUND'\n\t| 'FUNNEL_NOT_HEADLESS'\n\t| 'BUNDLE_TOO_LARGE'\n\t| 'PAGE_SIZE'\n\t| 'INVALID_PAGE'\n\t| 'NO_PAGES'\n\t| 'NO_PROJECTS'\n\t| 'MISSING_PROJECT_ID'\n\t| 'MISSING_INITIAL_PAGE_KEY'\n\t| 'API_ERROR'\n\t| 'PUBLISH_FAILED'\n\nexport class CLIError extends Error {\n\tcode: ErrorCode\n\thint?: string\n\tstatusCode?: number\n\n\tconstructor(code: ErrorCode, message: string, hint?: string) {\n\t\tsuper(message)\n\t\tthis.name = 'CLIError'\n\t\tthis.code = code\n\t\tthis.hint = hint\n\t}\n}\n\nexport function formatError(err: CLIError): string {\n\tconst lines = [\n\t\t`${pc.red('ERROR')} ${pc.dim(`[${err.code}]`)}: ${err.message}`,\n\t]\n\tif (err.hint) {\n\t\tlines.push(` ${pc.dim('Hint:')} ${err.hint}`)\n\t}\n\treturn lines.join('\\n')\n}\n\nexport function formatWarning(\n\tcode: string,\n\tmessage: string,\n\thint?: string\n): string {\n\tconst lines = [`${pc.yellow('WARNING')} ${pc.dim(`[${code}]`)}: ${message}`]\n\tif (hint) {\n\t\tlines.push(` ${pc.dim('Hint:')} ${hint}`)\n\t}\n\treturn lines.join('\\n')\n}\n","import pc from 'picocolors'\nimport ora, { type Ora } from 'ora'\n\nexport function success(msg: string): void {\n console.log(`${pc.green('✓')} ${msg}`)\n}\n\nexport function error(msg: string): void {\n console.error(`${pc.red('✗')} ${msg}`)\n}\n\nexport function warn(msg: string): void {\n console.warn(`${pc.yellow('!')} ${msg}`)\n}\n\nexport function info(msg: string): void {\n console.log(`${pc.blue('ℹ')} ${msg}`)\n}\n\nexport function dim(msg: string): void {\n console.log(pc.dim(msg))\n}\n\nexport function spinner(msg: string): Ora {\n return ora({ text: msg, color: 'cyan' }).start()\n}\n\nexport function banner(): void {\n console.log()\n console.log(` ${pc.bold('appfunnel')} ${pc.dim('v' + __CLI_VERSION__)}`)\n console.log()\n}\n","import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport { CLIError } from './errors.js'\n\nexport interface Credentials {\n token: string\n userId: string\n email: string\n expiresAt: string\n}\n\nconst CREDENTIALS_PATH = join(homedir(), '.appfunnelrc')\n\nexport function readCredentials(): Credentials | null {\n try {\n const raw = readFileSync(CREDENTIALS_PATH, 'utf-8')\n const data = JSON.parse(raw)\n if (!data.token) return null\n return data as Credentials\n } catch {\n return null\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const dir = homedir()\n mkdirSync(dir, { recursive: true })\n writeFileSync(CREDENTIALS_PATH, JSON.stringify(creds, null, 2) + '\\n', 'utf-8')\n}\n\nexport function requireAuth(): Credentials {\n const creds = readCredentials()\n if (!creds) {\n throw new CLIError(\n 'AUTH_REQUIRED',\n 'Not logged in.',\n \"Run 'appfunnel login' to authenticate.\",\n )\n }\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt)\n if (expiresAt < new Date()) {\n throw new CLIError(\n 'AUTH_EXPIRED',\n 'Token expired.',\n \"Run 'appfunnel login' to re-authenticate.\",\n )\n }\n }\n\n return creds\n}\n","import pc from 'picocolors'\nimport select from '@inquirer/select'\nimport * as log from './logger.js'\nimport { CLIError } from './errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\nexport interface Project {\n id: string\n name: string\n role: string\n}\n\nexport async function fetchProjects(token: string): Promise<Project[]> {\n const response = await fetch(`${DEFAULT_API_BASE}/user/projects`, {\n headers: {\n Authorization: token,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n throw new CLIError('API_ERROR', 'Failed to fetch projects.')\n }\n\n const body = (await response.json()) as { data: Project[] }\n return body.data\n}\n\n/**\n * Prompt the user to select a project from their available projects.\n * Returns the selected project ID.\n */\nexport async function promptForProject(token: string): Promise<string> {\n const spin = log.spinner('Fetching projects...')\n let projects: Project[]\n try {\n projects = await fetchProjects(token)\n } catch (err) {\n spin.stop()\n if (err instanceof CLIError) throw err\n throw new CLIError(\n 'API_ERROR',\n 'Failed to reach the API. Check your internet connection.',\n )\n }\n spin.stop()\n\n if (projects.length === 0) {\n throw new CLIError(\n 'NO_PROJECTS',\n 'No projects found.',\n 'Create a project at https://appfunnel.net first.',\n )\n }\n\n return select({\n message: 'Select a project',\n choices: projects.map((p) => ({\n name: `${p.name} ${pc.dim(`(${p.id})`)}`,\n value: p.id,\n })),\n })\n}\n","import { CLIError } from './errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\ninterface ApiOptions {\n\ttoken: string\n\tapiBaseUrl?: string\n}\n\nasync function apiFetch(\n\tpath: string,\n\toptions: ApiOptions & RequestInit\n): Promise<Response> {\n\tconst { token, apiBaseUrl, ...fetchOpts } = options\n\tconst base = apiBaseUrl || DEFAULT_API_BASE\n\tconst url = `${base}${path}`\n\n\t// Don't set Content-Type for FormData — let the browser set the boundary\n\tconst isFormData = fetchOpts.body instanceof FormData\n\tconst headers: Record<string, string> = {\n\t\tAuthorization: token,\n\t\t...((fetchOpts.headers as Record<string, string>) || {}),\n\t}\n\tif (!isFormData) {\n\t\theaders['Content-Type'] = 'application/json'\n\t}\n\n\tconst response = await fetch(url, {\n\t\t...fetchOpts,\n\t\theaders,\n\t})\n\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => '')\n\t\tlet message = `API request failed: ${response.status} ${response.statusText}`\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(body)\n\t\t\tif (parsed.error) message = parsed.error\n\t\t\tif (parsed.message) message = parsed.message\n\t\t} catch {\n\t\t\t/* ignore parse errors */\n\t\t}\n\t\tconst error = new CLIError('API_ERROR', message)\n\t\terror.statusCode = response.status\n\t\tthrow error\n\t}\n\n\treturn response\n}\n\n/**\n * Fetch enriched price data for all store price IDs.\n */\nexport async function fetchPrices(\n\tprojectId: string,\n\tstorePriceIds: string[],\n\toptions: ApiOptions\n): Promise<Map<string, unknown>> {\n\tif (storePriceIds.length === 0) return new Map()\n\n\tconst response = await apiFetch(`/project/${projectId}/headless/prices`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ storePriceIds }),\n\t})\n\n\tconst data = (await response.json()) as { prices: Record<string, unknown> }\n\treturn new Map(Object.entries(data.prices || {}))\n}\n\n/* ---------- Store & price listing (for template init) ---------- */\n\nexport interface Store {\n\tid: string\n\tname: string\n\ttype: 'STRIPE' | 'PADDLE'\n\tisTestMode: boolean\n}\n\nexport interface StorePrice {\n\tid: string\n\tstoreId: string\n\tname: string | null\n\tpriceName: string | null\n\tdisplayName: string | null\n\tamount: number\n\tcurrency: string\n\tinterval: string | null\n\tintervalCount: number\n}\n\n/**\n * Fetch all stores for a project.\n */\nexport async function fetchStores(\n\tprojectId: string,\n\toptions: ApiOptions\n): Promise<Store[]> {\n\tconst response = await apiFetch(`/project/${projectId}/stores`, {\n\t\t...options,\n\t\tmethod: 'GET',\n\t})\n\tconst data = (await response.json()) as { data: Store[] }\n\treturn data.data || []\n}\n\n/**\n * Fetch all prices for a store.\n */\nexport async function fetchStorePrices(\n\tprojectId: string,\n\tstoreId: string,\n\toptions: ApiOptions\n): Promise<StorePrice[]> {\n\tconst response = await apiFetch(\n\t\t`/project/${projectId}/stores/${storeId}/prices`,\n\t\t{ ...options, method: 'GET' }\n\t)\n\tconst data = (await response.json()) as { data: StorePrice[] }\n\treturn data.data || []\n}\n\n/**\n * Fetch all prices across all stores for a project.\n * Returns prices annotated with store info for display.\n */\nexport async function fetchAllProjectPrices(\n\tprojectId: string,\n\toptions: ApiOptions\n): Promise<Array<StorePrice & { store: Store }>> {\n\tconst stores = await fetchStores(projectId, options)\n\tconst all: Array<StorePrice & { store: Store }> = []\n\n\tfor (const store of stores) {\n\t\tconst prices = await fetchStorePrices(projectId, store.id, options)\n\t\tfor (const price of prices) {\n\t\t\tall.push({ ...price, store })\n\t\t}\n\t}\n\n\treturn all\n}\n\n/**\n * Publish a headless build.\n * If funnelId is empty, the server auto-creates a new headless funnel + campaign.\n */\nexport async function publishBuild(\n\tprojectId: string,\n\tfunnelId: string,\n\tmanifest: unknown,\n\tassets: Array<{ path: string; content: Buffer; contentType: string }>,\n\toptions: ApiOptions,\n\tpromote?: boolean\n): Promise<{ buildId: string; funnelId: string; created: boolean; activated: boolean; dashboardUrl: string; message: string }> {\n\tconst formData = new FormData()\n\tformData.set('manifest', JSON.stringify(manifest))\n\tif (funnelId) {\n\t\tformData.set('funnelId', funnelId)\n\t}\n\tif (promote) {\n\t\tformData.set('promote', 'true')\n\t}\n\n\tfor (const asset of assets) {\n\t\tformData.append(\n\t\t\t'assets',\n\t\t\tnew Blob([new Uint8Array(asset.content)], { type: asset.contentType }),\n\t\t\tasset.path\n\t\t)\n\t}\n\n\ttry {\n\t\tconst response = await apiFetch(`/project/${projectId}/headless/publish`, {\n\t\t\t...options,\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t})\n\t\treturn (await response.json()) as { buildId: string; funnelId: string; created: boolean; activated: boolean; dashboardUrl: string; message: string }\n\t} catch (err) {\n\t\tif (err instanceof CLIError && err.code === 'API_ERROR') {\n\t\t\tif (err.statusCode === 413) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'BUNDLE_TOO_LARGE',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Reduce page bundle sizes. Check for large dependencies.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (err.statusCode === 409) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'FUNNEL_NOT_HEADLESS',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Remove funnelId from config to create a new headless funnel.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow new CLIError('PUBLISH_FAILED', err.message)\n\t\t}\n\t\tthrow err\n\t}\n}\n","import { cpSync, existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport pc from 'picocolors'\nimport select from '@inquirer/select'\nimport input from '@inquirer/input'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { fetchProjects, promptForProject } from '../lib/projects.js'\nimport { fetchStores, fetchStorePrices, type Store, type StorePrice } from '../lib/api.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\n/* ---------- Template types ---------- */\n\ninterface TemplateProduct {\n\tid: string\n\tlabel: string\n\tdescription?: string\n\tpaidTrial?: boolean\n}\n\ninterface TemplateConfig {\n\tname: string\n\tdescription: string\n\tproducts: TemplateProduct[]\n}\n\n/* ---------- Helpers ---------- */\n\nfunction getTemplatesDir(): string {\n\tconst dir = join(__dirname, '..', 'templates')\n\tif (!existsSync(dir)) {\n\t\tthrow new Error(`Templates directory not found at ${dir}`)\n\t}\n\treturn dir\n}\n\nfunction listTemplates(): Array<{ dir: string; config: TemplateConfig }> {\n\tconst root = getTemplatesDir()\n\treturn readdirSync(root, { withFileTypes: true })\n\t\t.filter((d) => d.isDirectory())\n\t\t.map((d) => {\n\t\t\tconst configPath = join(root, d.name, 'template.json')\n\t\t\tconst config: TemplateConfig = existsSync(configPath)\n\t\t\t\t? JSON.parse(readFileSync(configPath, 'utf-8'))\n\t\t\t\t: { name: d.name, description: '', products: [] }\n\t\t\treturn { dir: d.name, config }\n\t\t})\n}\n\nconst INTERVAL_LABELS: Record<string, Record<number, string>> = {\n\tday: { 1: 'day', 7: 'week', 14: '2 weeks', 30: 'month' },\n\tweek: { 1: 'week', 2: '2 weeks', 4: 'month', 12: 'quarter', 52: 'year' },\n\tmonth: { 1: 'month', 3: 'quarter', 6: '6 months', 12: 'year' },\n\tyear: { 1: 'year' },\n}\n\nfunction formatInterval(interval: string | null, count: number): string {\n\tif (!interval) return ' one-time'\n\tconst label = INTERVAL_LABELS[interval]?.[count]\n\tif (label) return `/${label}`\n\treturn `/${count} ${interval}${count > 1 ? 's' : ''}`\n}\n\nfunction formatPrice(price: StorePrice): string {\n\tconst amount = (price.amount / 100).toFixed(2)\n\tconst currency = price.currency.toUpperCase()\n\tconst interval = formatInterval(price.interval, price.intervalCount)\n\n\tconst productName = price.name || 'Unnamed product'\n\tconst priceName = price.priceName ? ` — ${price.priceName}` : ''\n\n\treturn `${currency} ${amount}${interval} ${pc.dim(`${productName}${priceName}`)} ${pc.dim(`(${price.id})`)}`\n}\n\nfunction formatStoreName(store: Store): string {\n\tconst test = store.isTestMode ? pc.yellow(' (test)') : ''\n\treturn `${store.name || store.type}${test}`\n}\n\n/* ---------- Main ---------- */\n\nexport async function initCommand(nameArg?: string): Promise<void> {\n\tconst creds = requireAuth()\n\tconst apiOpts = { token: creds.token }\n\n\t// 1. Use provided name or ask interactively\n\tconst name = nameArg?.trim() || await input({\n\t\tmessage: 'Funnel name',\n\t\tvalidate: (value) => {\n\t\t\tif (!value.trim()) return 'Name is required'\n\t\t\tif (!/^[a-z0-9-]+$/.test(value.trim()))\n\t\t\t\treturn 'Use lowercase letters, numbers, and hyphens only'\n\t\t\tif (existsSync(join(process.cwd(), value.trim())))\n\t\t\t\treturn `Directory '${value.trim()}' already exists`\n\t\t\treturn true\n\t\t},\n\t})\n\n\t// Validate name if provided as argument\n\tif (nameArg) {\n\t\tif (!/^[a-z0-9-]+$/.test(name))\n\t\t\tthrow new Error('Name must be lowercase letters, numbers, and hyphens only')\n\t\tif (existsSync(join(process.cwd(), name)))\n\t\t\tthrow new Error(`Directory '${name}' already exists`)\n\t}\n\n\tconst dir = join(process.cwd(), name.trim())\n\n\t// 2. Select project\n\tconst projectId = await promptForProject(creds.token)\n\tconst projects = await fetchProjects(creds.token)\n\tconst project = projects.find((p) => p.id === projectId)!\n\n\t// 3. Select template\n\tconst templates = listTemplates()\n\tconst selectedDir = await select({\n\t\tmessage: 'Choose a template',\n\t\tchoices: templates.map((t) => ({\n\t\t\tname: t.config.description\n\t\t\t\t? `${t.config.name} — ${pc.dim(t.config.description)}`\n\t\t\t\t: t.config.name,\n\t\t\tvalue: t.dir,\n\t\t})),\n\t})\n\tconst chosen = templates.find((t) => t.dir === selectedDir)!\n\n\tconst templateConfig = chosen.config\n\tconst templateDir = join(getTemplatesDir(), chosen.dir)\n\n\t// 3. If template has products, select store + bind prices\n\tconst productBindings: Array<{\n\t\tid: string\n\t\tname: string\n\t\tstorePriceId: string\n\t\ttrialDays?: number\n\t\ttrialStorePriceId?: string\n\t}> = []\n\n\tif (templateConfig.products.length > 0) {\n\t\t// Fetch stores\n\t\tconst storesSpinner = log.spinner('Fetching stores...')\n\t\tconst stores = await fetchStores(projectId, apiOpts)\n\t\tstoresSpinner.stop()\n\n\t\tif (stores.length === 0) {\n\t\t\tlog.warn('No stores found for this project.')\n\t\t\tlog.info('Products will use empty IDs — create a store in the dashboard and update appfunnel.config.ts.')\n\t\t} else {\n\t\t\t// Select store\n\t\t\tlet store: Store\n\t\t\tif (stores.length === 1) {\n\t\t\t\tstore = stores[0]\n\t\t\t\tlog.info(`Using store: ${formatStoreName(store)}`)\n\t\t\t} else {\n\t\t\t\tconst storeId = await select({\n\t\t\t\t\tmessage: 'Choose a store',\n\t\t\t\t\tchoices: stores.map((s) => ({\n\t\t\t\t\t\tname: formatStoreName(s),\n\t\t\t\t\t\tvalue: s.id,\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tstore = stores.find((s) => s.id === storeId)!\n\t\t\t}\n\n\t\t\t// Fetch prices from selected store\n\t\t\tconst pricesSpinner = log.spinner('Fetching prices...')\n\t\t\tconst prices = await fetchStorePrices(projectId, store.id, apiOpts)\n\t\t\tpricesSpinner.stop()\n\n\t\t\tif (prices.length === 0) {\n\t\t\t\tlog.warn('No prices found in this store.')\n\t\t\t\tlog.info('Import prices in the dashboard, then update appfunnel.config.ts.')\n\t\t\t} else {\n\t\t\t\tconsole.log()\n\t\t\t\tlog.info(`Configuring ${templateConfig.products.length} product(s)...`)\n\t\t\t\tconsole.log()\n\n\t\t\t\tfor (const product of templateConfig.products) {\n\t\t\t\t\tif (product.description) {\n\t\t\t\t\t\tconsole.log(` ${pc.dim(product.description)}`)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Select main price\n\t\t\t\t\tconst storePriceId = await select({\n\t\t\t\t\t\tmessage: `${product.label} — select a price`,\n\t\t\t\t\t\tchoices: prices.map((p) => ({\n\t\t\t\t\t\t\tname: formatPrice(p),\n\t\t\t\t\t\t\tvalue: p.id,\n\t\t\t\t\t\t})),\n\t\t\t\t\t})\n\n\t\t\t\t\tconst binding: (typeof productBindings)[number] = {\n\t\t\t\t\t\tid: product.id,\n\t\t\t\t\t\tname: product.id,\n\t\t\t\t\t\tstorePriceId,\n\t\t\t\t\t}\n\n\t\t\t\t\t// Select trial price if needed\n\t\t\t\t\tif (product.paidTrial) {\n\t\t\t\t\t\tconst trialStorePriceId = await select({\n\t\t\t\t\t\t\tmessage: `${product.label} — select a trial price`,\n\t\t\t\t\t\t\tchoices: [\n\t\t\t\t\t\t\t\t...prices.map((p) => ({\n\t\t\t\t\t\t\t\t\tname: formatPrice(p),\n\t\t\t\t\t\t\t\t\tvalue: p.id,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t{ name: pc.dim('Skip (no trial)'), value: '' },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\n\t\t\t\t\t\tif (trialStorePriceId) {\n\t\t\t\t\t\t\tbinding.trialStorePriceId = trialStorePriceId\n\n\t\t\t\t\t\t\tconst trialDaysStr = await select({\n\t\t\t\t\t\t\t\tmessage: `${product.label} — trial duration`,\n\t\t\t\t\t\t\t\tchoices: [\n\t\t\t\t\t\t\t\t\t{ name: '3 days', value: '3' },\n\t\t\t\t\t\t\t\t\t{ name: '7 days', value: '7' },\n\t\t\t\t\t\t\t\t\t{ name: '14 days', value: '14' },\n\t\t\t\t\t\t\t\t\t{ name: '30 days', value: '30' },\n\t\t\t\t\t\t\t\t\t{ name: '90 days', value: '90' },\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbinding.trialDays = parseInt(trialDaysStr, 10)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tproductBindings.push(binding)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Copy template\n\tconst s = log.spinner(`Creating ${name}...`)\n\n\tcpSync(templateDir, dir, { recursive: true })\n\n\t// Remove template.json from output — it's not part of the user's project\n\tconst templateJsonPath = join(dir, 'template.json')\n\tif (existsSync(templateJsonPath)) {\n\t\tconst { unlinkSync } = await import('node:fs')\n\t\tunlinkSync(templateJsonPath)\n\t}\n\n\t// npm strips .gitignore from published packages, so we ship it as 'gitignore' and rename here\n\tconst gitignoreSrc = join(dir, 'gitignore')\n\tif (existsSync(gitignoreSrc)) {\n\t\tconst { renameSync } = await import('node:fs')\n\t\trenameSync(gitignoreSrc, join(dir, '.gitignore'))\n\t}\n\n\t// 5. Replace placeholders in appfunnel.config.ts\n\tconst configPath = join(dir, 'appfunnel.config.ts')\n\tif (existsSync(configPath)) {\n\t\tlet config = readFileSync(configPath, 'utf-8')\n\t\tconfig = config.replace('__PROJECT_ID__', projectId)\n\t\tconfig = config.replace('__NAME__', name)\n\n\t\t// If we have product bindings, replace the products section\n\t\tif (productBindings.length > 0) {\n\t\t\tconst itemsStr = productBindings\n\t\t\t\t.map((b) => {\n\t\t\t\t\tconst fields = [\n\t\t\t\t\t\t`\\t\\t\\t{ id: '${b.id}'`,\n\t\t\t\t\t\t`name: '${b.name}'`,\n\t\t\t\t\t\t`storePriceId: '${b.storePriceId}'`,\n\t\t\t\t\t]\n\t\t\t\t\tif (b.trialDays) fields.push(`trialDays: ${b.trialDays}`)\n\t\t\t\t\tif (b.trialStorePriceId)\n\t\t\t\t\t\tfields.push(`trialStorePriceId: '${b.trialStorePriceId}'`)\n\t\t\t\t\treturn fields.join(', ') + ' }'\n\t\t\t\t})\n\t\t\t\t.join(',\\n')\n\n\t\t\tconst defaultId = productBindings[0].id\n\t\t\tconfig = config.replace(\n\t\t\t\t/products:\\s*\\{[^}]*items:\\s*\\[[^\\]]*\\][^}]*\\}/s,\n\t\t\t\t`products: {\\n\\t\\titems: [\\n${itemsStr},\\n\\t\\t],\\n\\t\\tdefaultId: '${defaultId}',\\n\\t}`\n\t\t\t)\n\t\t}\n\n\t\twriteFileSync(configPath, config)\n\t}\n\n\t// 6. Generate package.json\n\tconst sdkVersion = `^${__CLI_VERSION__}`\n\n\twriteFileSync(\n\t\tjoin(dir, 'package.json'),\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tversion: '0.1.0',\n\t\t\t\tprivate: true,\n\t\t\t\ttype: 'module',\n\t\t\t\tscripts: {\n\t\t\t\t\tdev: 'appfunnel dev',\n\t\t\t\t\tbuild: 'appfunnel build',\n\t\t\t\t\tpublish: 'appfunnel publish',\n\t\t\t\t},\n\t\t\t\tdependencies: {\n\t\t\t\t\t'@appfunnel-dev/sdk': sdkVersion,\n\t\t\t\t\treact: '^18.3.0',\n\t\t\t\t\t'react-dom': '^18.3.0',\n\t\t\t\t},\n\t\t\t\tdevDependencies: {\n\t\t\t\t\tappfunnel: sdkVersion,\n\t\t\t\t\ttypescript: '^5.4.0',\n\t\t\t\t\t'@types/react': '^18.2.0',\n\t\t\t\t\t'@types/react-dom': '^18.2.0',\n\t\t\t\t\tvite: '^6.0.0',\n\t\t\t\t\t'@vitejs/plugin-react': '^4.0.0',\n\t\t\t\t\ttailwindcss: '^4.0.0',\n\t\t\t\t\t'@tailwindcss/vite': '^4.0.0',\n\t\t\t\t},\n\t\t\t},\n\t\t\tnull,\n\t\t\t2\n\t\t) + '\\n'\n\t)\n\n\ts.stop()\n\n\tconsole.log()\n\tlog.success(`Created ${pc.bold(name)} for project ${pc.bold(project.name)}`)\n\tconsole.log()\n\tconsole.log(` ${pc.dim('cd')} ${name}`)\n\tconsole.log(` ${pc.dim('npm install')}`)\n\tconsole.log(` ${pc.dim('appfunnel dev')}`)\n\tconsole.log()\n}\n","import { createServer } from 'node:http'\nimport { randomUUID } from 'node:crypto'\nimport open from 'open'\nimport * as log from '../lib/logger.js'\nimport { writeCredentials } from '../lib/auth.js'\n\nconst AUTH_BASE_URL = 'https://appfunnel.net'\nconst TIMEOUT_MS = 120_000 // 2 minutes\n\nexport async function loginCommand(): Promise<void> {\n\tconst state = randomUUID()\n\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst server = createServer((req, res) => {\n\t\t\tconst url = new URL(req.url || '/', `http://localhost`)\n\t\t\tif (url.pathname !== '/callback') {\n\t\t\t\tres.writeHead(404)\n\t\t\t\tres.end('Not found')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst token = url.searchParams.get('token')\n\t\t\tconst returnedState = url.searchParams.get('state')\n\t\t\tconst userId = url.searchParams.get('userId') || ''\n\t\t\tconst email = url.searchParams.get('email') || ''\n\t\t\tconst expiresAt = url.searchParams.get('expiresAt') || ''\n\n\t\t\tif (returnedState !== state) {\n\t\t\t\tres.writeHead(400)\n\t\t\t\tres.end('Invalid state parameter. Please try again.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (!token) {\n\t\t\t\tres.writeHead(400)\n\t\t\t\tres.end('No token received. Please try again.')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Store credentials\n\t\t\twriteCredentials({ token, userId, email, expiresAt })\n\n\t\t\t// Send success page\n\t\t\tres.writeHead(200, { 'Content-Type': 'text/html' })\n\t\t\tres.end(`\n <!DOCTYPE html>\n <html>\n <body style=\"font-family: system-ui; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;\">\n <div style=\"text-align: center;\">\n <h1>Logged in!</h1>\n <p>You can close this tab and return to the terminal.</p>\n </div>\n </body>\n </html>\n `)\n\n\t\t\t// Clean up\n\t\t\tspinner.stop()\n\t\t\tlog.success(`Logged in as ${email || userId}`)\n\t\t\tserver.close()\n\t\t\tresolve()\n\t\t})\n\n\t\t// Listen on random port\n\t\tserver.listen(0, '127.0.0.1', () => {\n\t\t\tconst addr = server.address()\n\t\t\tif (!addr || typeof addr === 'string') {\n\t\t\t\treject(new Error('Failed to start local server'))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst port = addr.port\n\t\t\tconst authUrl = `${AUTH_BASE_URL}/cli/authorize?port=${port}&state=${state}`\n\n\t\t\tlog.info('Opening browser for authentication...')\n\t\t\topen(authUrl).catch(() => {\n\t\t\t\tlog.warn(`Could not open browser. Please visit:\\n ${authUrl}`)\n\t\t\t})\n\t\t})\n\n\t\tconst spinner = log.spinner('Waiting for authentication...')\n\n\t\t// Timeout\n\t\tconst timeout = setTimeout(() => {\n\t\t\tspinner.stop()\n\t\t\tserver.close()\n\t\t\treject(new Error('Authentication timed out. Please try again.'))\n\t\t}, TIMEOUT_MS)\n\n\t\tserver.on('close', () => clearTimeout(timeout))\n\t})\n}\n","import pc from 'picocolors'\nimport { requireAuth } from '../lib/auth.js'\nimport { CLIError } from '../lib/errors.js'\nimport * as logger from '../lib/logger.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\nexport async function whoamiCommand(): Promise<void> {\n const creds = requireAuth()\n\n const spin = logger.spinner('Verifying credentials…')\n\n try {\n const response = await fetch(`${DEFAULT_API_BASE}/user`, {\n headers: {\n Authorization: creds.token,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!response.ok) {\n spin.stop()\n throw new CLIError(\n 'AUTH_EXPIRED',\n 'Token is no longer valid.',\n \"Run 'appfunnel login' to re-authenticate.\",\n )\n }\n\n const user = (await response.json()) as { email: string; id: string }\n spin.stop()\n\n logger.success(`Logged in as ${pc.bold(user.email)}`)\n logger.info(`User ID: ${pc.dim(user.id)}`)\n\n if (creds.expiresAt) {\n const expiresAt = new Date(creds.expiresAt)\n logger.info(`Token expires: ${pc.dim(expiresAt.toLocaleString())}`)\n }\n } catch (err) {\n spin.stop()\n if (err instanceof CLIError) throw err\n throw new CLIError(\n 'API_ERROR',\n 'Failed to reach the API. Check your internet connection.',\n )\n }\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { CLIError } from './errors.js'\n\nexport interface VariableConfig {\n type: string\n default?: unknown\n persist?: boolean\n}\n\nexport interface AppFunnelConfig {\n projectId: string\n name: string\n funnelId?: string\n initialPageKey: string\n defaultLocale?: string\n /** Response variables — stored as answers.* */\n responses?: Record<string, VariableConfig>\n /** Query param variables — stored as query.* */\n queryParams?: Record<string, VariableConfig>\n /** Data variables — stored as data.* */\n data?: Record<string, VariableConfig>\n products?: {\n items: Array<{ id: string; name: string; storePriceId: string; trialDays?: number; trialStorePriceId?: string }>\n defaultId?: string\n }\n integrations?: Record<string, Record<string, unknown>>\n pages?: Record<string, { name: string; type: string; slug?: string }>\n routes?: Record<string, Array<{ to: string; when?: unknown }>>\n}\n\nconst CONFIG_FILE = 'appfunnel.config.ts'\n\n/**\n * Load and evaluate the appfunnel.config.ts file using esbuild (a Vite dep).\n */\nexport async function loadConfig(cwd: string): Promise<AppFunnelConfig> {\n const configPath = join(cwd, CONFIG_FILE)\n\n if (!existsSync(configPath)) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n `No ${CONFIG_FILE} found in ${cwd}.`,\n \"Run 'appfunnel init' to create a new project, or cd into your project directory.\",\n )\n }\n\n // Use esbuild (already installed as a Vite dep) to transpile TS → JS\n const { transform } = await import('esbuild')\n const raw = readFileSync(configPath, 'utf-8')\n\n const result = await transform(raw, {\n loader: 'ts',\n format: 'esm',\n target: 'es2022',\n })\n\n // Evaluate the transpiled code\n // Strip the import of defineConfig since it's just a passthrough\n const code = result.code\n .replace(/import\\s*\\{[^}]*\\}\\s*from\\s*['\"]@appfunnel-dev\\/sdk['\"]\\s*;?/g, '')\n .replace(/\\bdefineConfig\\s*\\(/g, '(')\n\n // Use dynamic import via data URI\n const dataUri = `data:text/javascript;base64,${Buffer.from(code).toString('base64')}`\n const mod = await import(dataUri)\n const config = mod.default as AppFunnelConfig\n\n if (!config) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n `Invalid config in ${CONFIG_FILE}.`,\n 'Make sure your config exports a valid object with defineConfig().',\n )\n }\n\n return config\n}\n\n/**\n * Resolve the absolute path to the project's src directory.\n */\nexport function resolveSrcDir(cwd: string): string {\n return resolve(cwd, 'src')\n}\n\n/**\n * Resolve the absolute path to the pages directory.\n */\nexport function resolvePagesDir(cwd: string): string {\n return resolve(cwd, 'src', 'pages')\n}\n","import { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { CLIError } from './errors.js'\n\ninterface PackageJson {\n\tversion: string\n}\n\n/**\n * Check that CLI major.minor matches the installed @appfunnel-dev/sdk version.\n */\nexport function checkVersionCompatibility(cwd: string): void {\n\tconst cliVersion = __CLI_VERSION__\n\tconst sdkVersion = getSdkVersion(cwd)\n\n\tconst [cliMajor, cliMinor] = cliVersion.split('.').map(Number)\n\tconst [sdkMajor, sdkMinor] = sdkVersion.split('.').map(Number)\n\n\tif (cliMajor !== sdkMajor || cliMinor !== sdkMinor) {\n\t\tthrow new CLIError(\n\t\t\t'VERSION_MISMATCH',\n\t\t\t`CLI version ${cliVersion} requires @appfunnel-dev/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,\n\t\t\t\"Run 'npm install @appfunnel-dev/sdk@latest' to update.\"\n\t\t)\n\t}\n}\n\nfunction getSdkVersion(cwd: string): string {\n\ttry {\n\t\tconst pkgPath = join(\n\t\t\tcwd,\n\t\t\t'node_modules',\n\t\t\t'@appfunnel-dev',\n\t\t\t'sdk',\n\t\t\t'package.json'\n\t\t)\n\t\tconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as PackageJson\n\t\treturn pkg.version\n\t} catch {\n\t\tthrow new CLIError(\n\t\t\t'VERSION_MISMATCH',\n\t\t\t'@appfunnel-dev/sdk is not installed.',\n\t\t\t\"Run 'npm install @appfunnel-dev/sdk' to install it.\"\n\t\t)\n\t}\n}\n","import { readdirSync, readFileSync, existsSync } from 'node:fs'\nimport { join, basename } from 'node:path'\nimport { resolvePagesDir } from '../lib/config.js'\nimport { CLIError } from '../lib/errors.js'\nimport type ts from 'typescript'\n\nexport interface PageDefinition {\n name: string\n type?: string\n slug?: string\n routes?: Array<{ to: string; when?: unknown }>\n}\n\n/**\n * Scan src/pages/ for .tsx files and return page keys.\n */\nexport function scanPages(cwd: string): string[] {\n const pagesDir = resolvePagesDir(cwd)\n\n if (!existsSync(pagesDir)) {\n throw new CLIError(\n 'NO_PAGES',\n 'No src/pages/ directory found.',\n 'Create src/pages/ and add at least one .tsx page file.',\n )\n }\n\n const files = readdirSync(pagesDir)\n .filter((f) => f.endsWith('.tsx') && !f.startsWith('_'))\n .map((f) => basename(f, '.tsx'))\n .sort()\n\n if (files.length === 0) {\n throw new CLIError(\n 'NO_PAGES',\n 'No page files found in src/pages/.',\n 'Add .tsx files to src/pages/. Each file is a funnel page.',\n )\n }\n\n return files\n}\n\n/**\n * Extract definePage() metadata from each page file using the TypeScript compiler API.\n */\nexport async function extractPageDefinitions(\n cwd: string,\n pageKeys: string[],\n): Promise<Record<string, PageDefinition>> {\n const ts = await import('typescript') as typeof import('typescript')\n const pagesDir = resolvePagesDir(cwd)\n const result: Record<string, PageDefinition> = {}\n\n for (const key of pageKeys) {\n const filePath = join(pagesDir, `${key}.tsx`)\n const source = readFileSync(filePath, 'utf-8')\n\n const definition = extractDefinePage(ts, source, filePath)\n if (definition) {\n result[key] = definition\n } else {\n // Page without definePage() — use defaults\n result[key] = {\n name: key,\n type: 'default',\n }\n }\n }\n\n return result\n}\n\n/**\n * Parse a single page file and extract the definePage() argument.\n */\nfunction extractDefinePage(\n ts: typeof import('typescript'),\n source: string,\n fileName: string,\n): PageDefinition | null {\n const sourceFile = ts.createSourceFile(\n fileName,\n source,\n ts.ScriptTarget.Latest,\n true,\n ts.ScriptKind.TSX,\n )\n\n let definition: PageDefinition | null = null\n\n function visit(node: ts.Node): void {\n // Look for: export const page = definePage({ ... })\n if (ts.isVariableStatement(node)) {\n const isExported = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.ExportKeyword,\n )\n if (!isExported) return\n\n for (const decl of node.declarationList.declarations) {\n if (\n ts.isIdentifier(decl.name) &&\n decl.name.text === 'page' &&\n decl.initializer &&\n ts.isCallExpression(decl.initializer)\n ) {\n const call = decl.initializer\n const callee = call.expression\n\n // Check if callee is \"definePage\"\n if (ts.isIdentifier(callee) && callee.text === 'definePage') {\n const arg = call.arguments[0]\n if (arg && ts.isObjectLiteralExpression(arg)) {\n definition = extractObjectLiteral(ts, arg) as unknown as PageDefinition\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n ts.forEachChild(sourceFile, visit)\n return definition\n}\n\n/**\n * Recursively extract a TypeScript object literal into a plain JS object.\n */\nfunction extractObjectLiteral(\n ts: typeof import('typescript'),\n node: ts.ObjectLiteralExpression,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const prop of node.properties) {\n if (!ts.isPropertyAssignment(prop)) continue\n if (!ts.isIdentifier(prop.name) && !ts.isStringLiteral(prop.name)) continue\n\n const key = ts.isIdentifier(prop.name) ? prop.name.text : prop.name.text\n result[key] = extractValue(ts, prop.initializer)\n }\n\n return result\n}\n\n/**\n * Extract a static value from a TypeScript AST node.\n */\nfunction extractValue(\n ts: typeof import('typescript'),\n node: ts.Expression,\n): unknown {\n // String literal\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text\n }\n\n // Numeric literal\n if (ts.isNumericLiteral(node)) {\n return Number(node.text)\n }\n\n // Boolean / null / undefined\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false\n if (node.kind === ts.SyntaxKind.NullKeyword) return null\n if (node.kind === ts.SyntaxKind.UndefinedKeyword) return undefined\n\n // Array literal\n if (ts.isArrayLiteralExpression(node)) {\n return node.elements.map((el) => extractValue(ts, el))\n }\n\n // Object literal\n if (ts.isObjectLiteralExpression(node)) {\n return extractObjectLiteral(ts, node)\n }\n\n // Prefix unary (negative numbers)\n if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken) {\n const operand = extractValue(ts, node.operand)\n if (typeof operand === 'number') return -operand\n }\n\n // Can't statically evaluate — return undefined\n return undefined\n}\n","import { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\n\ninterface EntryOptions {\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n pagesDir: string\n funnelTsxPath: string\n isDev: boolean\n priceData?: Map<string, unknown>\n translations?: Record<string, Record<string, string>>\n}\n\n/**\n * Generate the virtual entry module source code.\n *\n * This creates a mini SPA that:\n * - Mounts FunnelProvider once\n * - Wraps with the user's funnel.tsx\n * - Client-side routes between pages via the SDK's Router\n * - Lazy-loads page components\n */\nexport function generateEntrySource(options: EntryOptions): string {\n const { config, pages, pagesDir, funnelTsxPath, isDev, translations } = options\n const pageKeys = Object.keys(pages)\n\n // Merge definePage() metadata into config\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Override config pages/routes with extracted ones\n const fullConfig = {\n ...config,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n }\n\n // Generate lazy imports for each page\n const pageImports = pageKeys\n .map(\n (key) =>\n ` '${key}': lazy(() => import('${join(pagesDir, key + '.tsx').replace(/\\\\/g, '/')}')),`,\n )\n .join('\\n')\n\n // Build slug → key mapping\n const slugMap: Record<string, string> = {}\n for (const [key, def] of Object.entries(pages)) {\n slugMap[def.slug || key] = key\n }\n\n // Serialize price data as a Map constructor call\n // In production, runtime data (prices, integrations, etc.) is injected via window.__APPFUNNEL_DATA__\n const priceDataCode = isDev\n ? (options.priceData && options.priceData.size > 0\n ? `const priceData = new Map(${JSON.stringify([...options.priceData.entries()])});`\n : `const priceData = undefined;`)\n : `const priceData = (() => {\n const rd = typeof window !== 'undefined' && window.__APPFUNNEL_DATA__;\n if (!rd || !rd.products?.items) return undefined;\n // Build price map from server-injected product data\n const map = new Map();\n for (const item of rd.products.items) {\n if (item.priceData && item.storePriceId) map.set(item.storePriceId, item.priceData);\n if (item.trialPriceData && item.trialStorePriceId) map.set(item.trialStorePriceId, item.trialPriceData);\n }\n return map.size > 0 ? map : undefined;\n})();`\n\n const trackingCode = isDev\n ? `\n// Dev mode: mock tracking — log events to console\nglobalThis.__APPFUNNEL_DEV__ = true;\n`\n : ''\n\n // Import app.css if it exists (Tailwind, global styles, etc.)\n const appCssPath = join(pagesDir, '..', 'app.css').replace(/\\\\/g, '/')\n const hasAppCss = existsSync(join(pagesDir, '..', 'app.css'))\n\n return `\nimport { StrictMode, Component, lazy, Suspense, useState, useCallback, useEffect, useTransition, useDeferredValue, useSyncExternalStore } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { FunnelProvider, useNavigation } from '@appfunnel-dev/sdk'\n${hasAppCss ? `import '${appCssPath}'` : ''}\nimport FunnelWrapper from '${funnelTsxPath.replace(/\\\\/g, '/')}'\n\n${trackingCode}\n\nconst pageComponents = {\n${pageImports}\n}\n\n${priceDataCode}\n\nconst translations = ${translations ? JSON.stringify(translations) : 'undefined'}\n\nconst config = ${JSON.stringify(fullConfig, null, 2)}\n\nconst keyToSlug = ${JSON.stringify(\n Object.fromEntries(Object.entries(slugMap).map(([s, k]) => [k, s])),\n )}\nconst slugToKey = ${JSON.stringify(slugMap)}\n\nconst DEV_CAMPAIGN_SLUG = 'campaign'\nconst DEFAULT_INITIAL = '${config.initialPageKey}'\n\n/**\n * Parse the URL to extract basePath, campaignSlug, and initial page.\n *\n * URL pattern: /f/<campaignSlug>[/<pageSlug>]\n *\n * In dev, redirects bare / to /f/<projectId> so the URL matches production.\n */\nfunction parseUrl() {\n const parts = window.location.pathname.split('/').filter(Boolean)\n\n // /f/<campaignSlug>[/<pageSlug>]\n if (parts[0] === 'f' && parts.length >= 2) {\n const campaignSlug = parts[1]\n const pageSlug = parts[2] || ''\n const pageKey = pageSlug ? (slugToKey[pageSlug] || '') : ''\n return {\n basePath: '/f/' + campaignSlug,\n campaignSlug,\n initialPage: pageKey || DEFAULT_INITIAL,\n }\n }\n\n // Bare URL → redirect to /f/<slug> in dev\n ${isDev ? `\n window.history.replaceState(null, '', '/f/' + DEV_CAMPAIGN_SLUG)\n return {\n basePath: '/f/' + DEV_CAMPAIGN_SLUG,\n campaignSlug: DEV_CAMPAIGN_SLUG,\n initialPage: DEFAULT_INITIAL,\n }` : `\n return {\n basePath: '',\n campaignSlug: '',\n initialPage: DEFAULT_INITIAL,\n }`}\n}\n\nconst { basePath, campaignSlug, initialPage } = parseUrl()\n\n${isDev ? `\nclass ErrorBoundary extends Component {\n constructor(props) {\n super(props)\n this.state = { error: null }\n }\n static getDerivedStateFromError(error) {\n return { error }\n }\n componentDidCatch(error, info) {\n console.error('[AppFunnel] Render error:', error, info)\n }\n render() {\n if (this.state.error) {\n return (\n <div style={{ padding: '2rem', fontFamily: 'monospace' }}>\n <h2 style={{ color: 'red' }}>AppFunnel Error</h2>\n <pre style={{ whiteSpace: 'pre-wrap', color: '#333' }}>{this.state.error.message}</pre>\n <pre style={{ whiteSpace: 'pre-wrap', color: '#666', fontSize: '12px' }}>{this.state.error.stack}</pre>\n </div>\n )\n }\n return this.props.children\n }\n}\n` : ''}\n\n/**\n * PageRenderer lives inside FunnelProvider so it can use SDK hooks.\n * Subscribes to the router — re-renders when the page changes.\n * Uses useTransition to keep showing the current page while the next one loads.\n */\nfunction PageRenderer() {\n const { currentPage, goToPage } = useNavigation()\n const routerPageKey = currentPage?.key || ''\n\n // Track the displayed page separately so we can transition smoothly\n const [displayedKey, setDisplayedKey] = useState(routerPageKey)\n const [isPending, startTransition] = useTransition()\n\n // When the router's page changes, transition to the new page\n useEffect(() => {\n if (routerPageKey && routerPageKey !== displayedKey) {\n startTransition(() => {\n setDisplayedKey(routerPageKey)\n })\n }\n }, [routerPageKey, displayedKey])\n\n // Sync URL with current page\n const slug = currentPage?.slug || routerPageKey\n useEffect(() => {\n const expectedPath = basePath ? basePath + '/' + slug : '/' + slug\n if (slug && window.location.pathname !== expectedPath) {\n window.history.pushState(null, '', expectedPath)\n }\n }, [slug])\n\n // Handle browser back/forward\n useEffect(() => {\n const handlePopState = () => {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n const key = slugToKey[path]\n if (key && key !== routerPageKey) {\n goToPage(key)\n }\n }\n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [routerPageKey, goToPage])\n\n const PageComponent = pageComponents[displayedKey]\n\n if (!PageComponent) {\n return <div style={{ padding: '2rem', color: 'red' }}>Page not found: {displayedKey}</div>\n }\n\n return (\n <Suspense fallback={null}>\n <PageComponent />\n </Suspense>\n )\n}\n\n// Runtime data injected by the server (production only)\nconst __rd = typeof window !== 'undefined' && window.__APPFUNNEL_DATA__\n\nfunction App() {\n // In production, merge server-injected integrations into config\n const runtimeConfig = __rd && __rd.integrations\n ? { ...config, integrations: { ...config.integrations, ...__rd.integrations } }\n : config\n\n const sessionData = __rd ? {\n campaignId: __rd.campaignId || '',\n funnelId: __rd.funnelId || config.funnelId || '',\n experimentId: __rd.experimentId || null,\n } : undefined\n\n return (\n <FunnelProvider\n config={runtimeConfig}\n initialPage={initialPage}\n basePath={basePath}\n campaignSlug={campaignSlug}\n priceData={priceData}\n sessionData={sessionData}\n translations={translations}\n >\n <FunnelWrapper>\n <PageRenderer />\n </FunnelWrapper>\n </FunnelProvider>\n )\n}\n\ncreateRoot(document.getElementById('root')).render(\n <StrictMode>\n ${isDev ? '<ErrorBoundary>' : ''}\n <App />\n ${isDev ? '</ErrorBoundary>' : ''}\n </StrictMode>\n)\n\n// Reveal body (the host page may set opacity:0 for a loading transition)\ndocument.body.style.opacity = '1'\n`\n}\n","/**\n * Generate the index.html template for the dev server and production build.\n */\nexport function generateHtml(title: string = 'AppFunnel'): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${title}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/@appfunnel/entry\"></script>\n </body>\n</html>`\n}\n","import { resolve, join } from 'node:path'\nimport { existsSync, writeFileSync, mkdirSync, readFileSync, readdirSync } from 'node:fs'\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\nimport { generateEntrySource } from './entry.js'\nimport { generateHtml } from './html.js'\n\nconst VIRTUAL_ENTRY_ID = '@appfunnel/entry'\nconst RESOLVED_VIRTUAL_ENTRY_ID = '\\0' + VIRTUAL_ENTRY_ID + '.tsx'\n\n/** Working directory for dev/build artifacts (like .next/) */\nconst APPFUNNEL_DIR = '.appfunnel'\n\ninterface PluginOptions {\n cwd: string\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n isDev: boolean\n priceData?: Map<string, unknown>\n onPagesChange?: () => Promise<void>\n}\n\n/**\n * Load all locale JSON files from <cwd>/locales/.\n * Returns a TranslationMap: { \"en\": { \"key\": \"value\" }, \"de\": { ... } }\n */\nfunction loadTranslations(cwd: string): Record<string, Record<string, string>> | undefined {\n const localesDir = join(cwd, 'locales')\n if (!existsSync(localesDir)) return undefined\n\n const translations: Record<string, Record<string, string>> = {}\n let hasAny = false\n\n for (const file of readdirSync(localesDir)) {\n if (!file.endsWith('.json')) continue\n const locale = file.replace(/\\.json$/, '')\n try {\n const content = readFileSync(join(localesDir, file), 'utf-8')\n translations[locale] = JSON.parse(content)\n hasAny = true\n } catch {\n // Skip invalid JSON files\n }\n }\n\n return hasAny ? translations : undefined\n}\n\nexport function appfunnelPlugin(options: PluginOptions): Plugin {\n const { cwd, config, isDev } = options\n let pages = options.pages\n const pagesDir = resolve(cwd, 'src', 'pages')\n const funnelTsxPath = resolve(cwd, 'src', 'funnel.tsx')\n const appfunnelDir = join(cwd, APPFUNNEL_DIR)\n const htmlPath = join(appfunnelDir, 'index.html')\n const localesDir = join(cwd, 'locales')\n\n function getEntrySource(): string {\n return generateEntrySource({\n config,\n pages,\n pagesDir,\n funnelTsxPath,\n isDev,\n priceData: options.priceData,\n translations: loadTranslations(cwd),\n })\n }\n\n return {\n name: 'appfunnel',\n\n config() {\n // Ensure .appfunnel/ exists and write the HTML shell\n mkdirSync(appfunnelDir, { recursive: true })\n writeFileSync(htmlPath, generateHtml(config.name || 'AppFunnel'))\n\n return {\n // Don't let Vite auto-serve index.html — we handle it ourselves\n appType: 'custom',\n resolve: {\n alias: {\n '@': resolve(cwd, 'src'),\n },\n dedupe: ['react', 'react-dom'],\n },\n esbuild: {\n jsx: 'automatic',\n },\n optimizeDeps: {\n include: ['react', 'react-dom', 'react/jsx-runtime'],\n force: true,\n },\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_ID || id === '/' + VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n return null\n },\n\n async load(id) {\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n const { transform } = await import('esbuild')\n const source = getEntrySource()\n const result = await transform(source, {\n loader: 'tsx',\n jsx: 'automatic',\n sourcefile: 'appfunnel-entry.tsx',\n })\n return result.code\n }\n return null\n },\n\n configureServer(devServer) {\n // Watch for page file additions/removals\n const watcher = devServer.watcher\n watcher.add(pagesDir)\n\n const handlePagesChange = async () => {\n if (options.onPagesChange) {\n await options.onPagesChange()\n }\n const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ENTRY_ID)\n if (mod) {\n devServer.moduleGraph.invalidateModule(mod)\n }\n devServer.ws.send({ type: 'full-reload' })\n }\n\n watcher.on('add', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n watcher.on('unlink', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n // Watch appfunnel.config.ts for changes → full reload\n const configPath = join(cwd, 'appfunnel.config.ts')\n if (existsSync(configPath)) {\n watcher.add(configPath)\n watcher.on('change', (file) => {\n if (file === configPath) {\n devServer.ws.send({ type: 'full-reload' })\n }\n })\n }\n\n // Watch locales/ for changes → full reload\n if (existsSync(localesDir)) {\n watcher.add(localesDir)\n watcher.on('change', (file) => {\n if (file.startsWith(localesDir) && file.endsWith('.json')) {\n const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ENTRY_ID)\n if (mod) {\n devServer.moduleGraph.invalidateModule(mod)\n }\n devServer.ws.send({ type: 'full-reload' })\n }\n })\n }\n\n // Since appType is 'custom', we serve HTML ourselves.\n // Registered after Vite internals so /@vite, /node_modules etc. resolve first.\n return () => {\n devServer.middlewares.use(async (req, res, next) => {\n const url = req.url?.split('?')[0] || ''\n\n // Let Vite handle static assets and internal routes\n if (url.includes('.') || url.startsWith('/@') || url.startsWith('/node_modules')) {\n return next()\n }\n\n try {\n const rawHtml = readFileSync(htmlPath, 'utf-8')\n const html = await devServer.transformIndexHtml(req.url || '/', rawHtml)\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html')\n res.end(html)\n } catch (err) {\n next(err)\n }\n })\n }\n },\n\n transformIndexHtml(html) {\n return html\n },\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, resolvePagesDir } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { promptForProject } from '../lib/projects.js'\nimport { fetchPrices } from '../lib/api.js'\n\nexport async function devCommand(options: { port?: number }): Promise<void> {\n const cwd = process.cwd()\n const port = options.port || 5173\n\n // 1. Auth check\n const creds = requireAuth()\n\n // 2. Version check\n checkVersionCompatibility(cwd)\n\n // 3. Load config\n const s = log.spinner('Loading config...')\n const config = await loadConfig(cwd)\n s.stop()\n\n // 4. If no projectId, prompt for one and update the config file\n if (!config.projectId) {\n log.info('No projectId found in appfunnel.config.ts')\n const projectId = await promptForProject(creds.token)\n config.projectId = projectId\n\n // Write projectId back to the config file\n const configPath = join(cwd, 'appfunnel.config.ts')\n const configSource = readFileSync(configPath, 'utf-8')\n let updated: string\n\n if (/projectId:\\s*['\"]/.test(configSource)) {\n // Replace existing projectId value\n updated = configSource.replace(\n /projectId:\\s*['\"].*?['\"]/,\n `projectId: '${projectId}'`,\n )\n } else {\n // Insert projectId after the opening of defineConfig({\n updated = configSource.replace(\n /(defineConfig\\(\\{[\\t ]*\\n)/,\n `$1\\tprojectId: '${projectId}',\\n`,\n )\n }\n\n if (updated !== configSource) {\n writeFileSync(configPath, updated)\n log.success(`Updated projectId in appfunnel.config.ts`)\n } else {\n log.warn(`Could not auto-update appfunnel.config.ts — add projectId: '${projectId}' manually.`)\n }\n }\n\n // 5. Scan and extract pages\n const s2 = log.spinner('Scanning pages...')\n let pageKeys = scanPages(cwd)\n let pages = await extractPageDefinitions(cwd, pageKeys)\n s2.stop()\n\n log.info(`Found ${pageKeys.length} pages: ${pageKeys.join(', ')}`)\n\n // 6. Fetch store prices (cached for dev session)\n let priceData: Map<string, unknown> = new Map()\n if (config.projectId && config.products?.items?.length) {\n try {\n const storePriceIds = [\n ...new Set(\n config.products.items.flatMap((item) =>\n [item.storePriceId, item.trialStorePriceId].filter(Boolean) as string[]\n )\n ),\n ]\n\n log.info(`Fetching ${storePriceIds.length} store prices: ${storePriceIds.join(', ')}`)\n\n const s3 = log.spinner('Fetching store prices...')\n priceData = await fetchPrices(config.projectId, storePriceIds, { token: creds.token })\n s3.stop()\n\n // Check that every requested price was returned\n const missingIds = storePriceIds.filter((id) => !priceData.has(id))\n if (missingIds.length > 0) {\n log.error(`Missing store prices: ${missingIds.join(', ')}`)\n log.error('Make sure these storePriceId values in your config match prices in your project.')\n process.exit(1)\n }\n\n log.success(`Fetched ${priceData.size}/${storePriceIds.length} store prices`)\n } catch (err) {\n log.error(`Failed to fetch store prices: ${(err as Error).message}`)\n process.exit(1)\n }\n }\n\n // 7. Start Vite dev server\n const { createServer } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n // Load @tailwindcss/vite from the user's project\n let tailwindPlugin: any = null\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(join(cwd, 'package.json'))\n const tailwindPath = require.resolve('@tailwindcss/vite')\n const tailwindVite = await import(tailwindPath)\n tailwindPlugin = tailwindVite.default\n } catch {\n // Not installed — skip\n }\n\n const server = await createServer({\n root: cwd,\n server: {\n port,\n strictPort: false,\n },\n plugins: [\n react.default(),\n ...(tailwindPlugin ? [tailwindPlugin()] : []),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: true,\n priceData,\n async onPagesChange() {\n // Re-scan pages when files are added/removed\n pageKeys = scanPages(cwd)\n pages = await extractPageDefinitions(cwd, pageKeys)\n log.info(`Pages updated: ${pageKeys.join(', ')}`)\n },\n }),\n ],\n css: {\n postcss: cwd,\n },\n })\n\n await server.listen()\n\n const address = server.resolvedUrls?.local?.[0] || `http://localhost:${port}`\n\n console.log()\n console.log(` ${pc.bold(config.name || 'AppFunnel')} dev server`)\n console.log()\n console.log(` ${pc.dim('Local:')} ${pc.cyan(address)}`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Tracking:')} ${pc.yellow('mocked (console)')}`)\n console.log()\n console.log(` ${pc.dim('Press')} ${pc.bold('Ctrl+C')} ${pc.dim('to stop')}`)\n console.log()\n}\n","import type { PageDefinition } from '../extract/pages.js'\n\ninterface SharedSegment {\n type: 'shared'\n pageKeys: string[]\n}\n\ninterface BranchSegment {\n type: 'branch'\n sourcePageKey: string\n arms: { pageKeys: string[] }[]\n}\n\nexport type FlowSegment = SharedSegment | BranchSegment\n\nexport interface ComputedFunnelFlow {\n initialPageKey: string\n segments: FlowSegment[]\n terminalPageKeys: string[]\n unreachablePageKeys: string[]\n}\n\n/**\n * Compute the segment-based flow through a funnel.\n *\n * Produces shared segments (linear page sequences) and branch segments\n * (where routes diverge, with variable-length arms that reconverge).\n *\n * Ported from api/src/utils/computeFunnelPaths.ts, adapted for CLI PageDefinition format.\n */\nexport function computeFunnelFlow(\n pages: Record<string, PageDefinition>,\n initialPageKey: string,\n): ComputedFunnelFlow {\n const allPageKeys = new Set(Object.keys(pages))\n\n if (allPageKeys.size === 0) {\n return { initialPageKey, segments: [], terminalPageKeys: [], unreachablePageKeys: [] }\n }\n\n // Build adjacency: pageKey → unique ordered target pageKeys\n function getTargets(pageKey: string): string[] {\n const routes = pages[pageKey]?.routes || []\n const seen = new Set<string>()\n const targets: string[] = []\n for (const route of routes) {\n if (allPageKeys.has(route.to) && !seen.has(route.to)) {\n seen.add(route.to)\n targets.push(route.to)\n }\n }\n return targets\n }\n\n // BFS from initial page to find reachable pages\n const reachable = new Set<string>()\n {\n const queue: string[] = []\n if (allPageKeys.has(initialPageKey)) {\n reachable.add(initialPageKey)\n queue.push(initialPageKey)\n }\n while (queue.length > 0) {\n const pageKey = queue.shift()!\n for (const target of getTargets(pageKey)) {\n if (!reachable.has(target)) {\n reachable.add(target)\n queue.push(target)\n }\n }\n }\n }\n\n const unreachablePageKeys: string[] = []\n const terminalPageKeys: string[] = []\n\n for (const pageKey of allPageKeys) {\n if (!reachable.has(pageKey)) {\n unreachablePageKeys.push(pageKey)\n continue\n }\n if (getTargets(pageKey).length === 0) {\n terminalPageKeys.push(pageKey)\n }\n }\n\n // BFS forward from a page to collect all reachable pageKeys with distances\n function bfsForward(start: string): Map<string, number> {\n const dist = new Map<string, number>()\n dist.set(start, 0)\n const queue = [start]\n while (queue.length > 0) {\n const current = queue.shift()!\n const d = dist.get(current)!\n for (const target of getTargets(current)) {\n if (!dist.has(target)) {\n dist.set(target, d + 1)\n queue.push(target)\n }\n }\n }\n return dist\n }\n\n // Find convergence page for branch arms\n function findConvergence(armStarts: string[]): string | null {\n if (armStarts.length === 0) return null\n\n const armReachable = armStarts.map((s) => bfsForward(s))\n const armStartSet = new Set(armStarts)\n\n let candidates = new Set<string>()\n for (const key of armReachable[0].keys()) {\n if (!armStartSet.has(key)) candidates.add(key)\n }\n for (let i = 1; i < armReachable.length; i++) {\n const reachSet = new Set(armReachable[i].keys())\n candidates = new Set([...candidates].filter((k) => reachSet.has(k)))\n }\n\n if (candidates.size === 0) return null\n\n let bestPage: string | null = null\n let bestMinDist = Infinity\n for (const pageKey of candidates) {\n const minDist = Math.min(...armReachable.map((r) => r.get(pageKey) ?? Infinity))\n if (minDist < bestMinDist) {\n bestMinDist = minDist\n bestPage = pageKey\n }\n }\n\n return bestPage\n }\n\n // Walk a branch arm from start to convergence\n function walkArm(start: string, convergence: string | null, globalVisited: Set<string>): string[] {\n if (convergence === null) {\n const pages: string[] = []\n let current = start\n while (true) {\n if (globalVisited.has(current)) break\n globalVisited.add(current)\n pages.push(current)\n const targets = getTargets(current)\n if (targets.length === 0) break\n const next = targets.find((t) => !globalVisited.has(t))\n if (!next) break\n current = next\n }\n return pages\n }\n\n // BFS from start to convergence\n const parent = new Map<string, string | null>()\n parent.set(start, null)\n const queue = [start]\n let found = false\n\n while (queue.length > 0 && !found) {\n const current = queue.shift()!\n for (const target of getTargets(current)) {\n if (!parent.has(target)) {\n parent.set(target, current)\n if (target === convergence) {\n found = true\n break\n }\n queue.push(target)\n }\n }\n }\n\n if (!found) {\n const pages: string[] = []\n let current = start\n while (true) {\n if (globalVisited.has(current)) break\n globalVisited.add(current)\n pages.push(current)\n const targets = getTargets(current)\n if (targets.length === 0) break\n const next = targets.find((t) => !globalVisited.has(t))\n if (!next) break\n current = next\n }\n return pages\n }\n\n const path: string[] = []\n let node: string | null = convergence\n while (node !== null && node !== start) {\n path.unshift(node)\n node = parent.get(node) ?? null\n }\n path.unshift(start)\n if (path[path.length - 1] === convergence) {\n path.pop()\n }\n\n for (const p of path) {\n globalVisited.add(p)\n }\n\n return path\n }\n\n // --- Main walk: build segments ---\n if (!allPageKeys.has(initialPageKey)) {\n return { initialPageKey, segments: [], terminalPageKeys, unreachablePageKeys }\n }\n\n const segments: FlowSegment[] = []\n const globalVisited = new Set<string>()\n let current: string | null = initialPageKey\n let sharedPages: string[] = []\n\n while (current !== null && !globalVisited.has(current)) {\n const targets = getTargets(current)\n\n if (targets.length === 0) {\n sharedPages.push(current)\n globalVisited.add(current)\n break\n }\n\n const uniqueTargets = [...new Set(targets)]\n\n if (uniqueTargets.length === 1) {\n sharedPages.push(current)\n globalVisited.add(current)\n current = uniqueTargets[0]\n continue\n }\n\n // Branch point\n sharedPages.push(current)\n globalVisited.add(current)\n segments.push({ type: 'shared', pageKeys: [...sharedPages] })\n sharedPages = []\n\n const convergence = findConvergence(uniqueTargets)\n\n const arms: { pageKeys: string[] }[] = []\n for (const armStart of uniqueTargets) {\n const armPages = walkArm(armStart, convergence, globalVisited)\n arms.push({ pageKeys: armPages })\n }\n\n segments.push({ type: 'branch', sourcePageKey: current, arms })\n\n if (convergence !== null && !globalVisited.has(convergence)) {\n current = convergence\n } else {\n current = null\n }\n }\n\n if (sharedPages.length > 0) {\n segments.push({ type: 'shared', pageKeys: sharedPages })\n }\n\n return { initialPageKey, segments, terminalPageKeys, unreachablePageKeys }\n}\n","import pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { loadConfig } from '../lib/config.js'\nimport { scanPages, extractPageDefinitions, type PageDefinition } from '../extract/pages.js'\nimport { computeFunnelFlow, type FlowSegment, type ComputedFunnelFlow } from '../lib/computeFlow.js'\n\nexport async function routesCommand(): Promise<void> {\n const cwd = process.cwd()\n\n const s = log.spinner('Analyzing pages...')\n const config = await loadConfig(cwd)\n const pageKeys = scanPages(cwd)\n const pages = await extractPageDefinitions(cwd, pageKeys)\n s.stop()\n\n const flow = computeFunnelFlow(pages, config.initialPageKey)\n\n console.log()\n console.log(` ${pc.bold(config.name)}`)\n console.log(` ${pc.dim(`${pageKeys.length} pages`)}`)\n console.log()\n\n renderFlow(flow, pages)\n}\n\n// ── Box-drawing characters ─────────────────────────────────────\n\nconst H = '─'\nconst V = '│'\n\nfunction renderFlow(flow: ComputedFunnelFlow, pages: Record<string, PageDefinition>): void {\n const indent = ' '\n\n for (let i = 0; i < flow.segments.length; i++) {\n const segment = flow.segments[i]\n\n if (segment.type === 'shared') {\n for (let j = 0; j < segment.pageKeys.length; j++) {\n const key = segment.pageKeys[j]\n const page = pages[key]\n const isStart = key === flow.initialPageKey\n const isTerminal = flow.terminalPageKeys.includes(key)\n printPageBox(indent, key, page, isStart, isTerminal)\n\n const isLastInSegment = j === segment.pageKeys.length - 1\n const hasNextSegment = i < flow.segments.length - 1\n if ((!isLastInSegment || hasNextSegment) && !isTerminal) {\n printArrow(indent)\n }\n }\n } else {\n renderBranch(indent, segment, pages, flow)\n\n if (i < flow.segments.length - 1) {\n printArrow(indent)\n }\n }\n }\n\n // Unreachable pages\n if (flow.unreachablePageKeys.length > 0) {\n console.log()\n console.log(` ${pc.yellow('⚠')} ${pc.yellow('Unreachable pages:')}`)\n for (const key of flow.unreachablePageKeys) {\n const page = pages[key]\n console.log(` ${pc.dim('•')} ${key}${page?.name ? pc.dim(` (${page.name})`) : ''}`)\n }\n }\n\n console.log()\n}\n\nfunction formatPageLabel(key: string, page: PageDefinition | undefined, isStart: boolean, isTerminal: boolean): string {\n const name = page?.name || key\n const type = page?.type\n const badges: string[] = []\n\n if (isStart) badges.push(pc.green('start'))\n if (isTerminal) badges.push(pc.red('end'))\n if (type && type !== 'default') badges.push(pc.magenta(type))\n\n const label = key === name.toLowerCase().replace(/\\s+/g, '-') ? name : `${name} ${pc.dim(`(${key})`)}`\n const badgeStr = badges.length > 0 ? ' ' + badges.map((b) => pc.dim('[') + b + pc.dim(']')).join(' ') : ''\n\n return label + badgeStr\n}\n\nfunction printPageBox(indent: string, key: string, page: PageDefinition | undefined, isStart: boolean, isTerminal: boolean): void {\n const label = formatPageLabel(key, page, isStart, isTerminal)\n const rawLen = stripAnsi(label).length\n const boxWidth = Math.max(rawLen + 2, 20)\n const padding = boxWidth - rawLen - 2\n\n console.log(`${indent}┌${H.repeat(boxWidth)}┐`)\n console.log(`${indent}│ ${label}${' '.repeat(padding)} │`)\n console.log(`${indent}└${H.repeat(boxWidth)}┘`)\n}\n\nfunction printArrow(indent: string): void {\n console.log(`${indent} ${V}`)\n console.log(`${indent} ▼`)\n}\n\nfunction renderBranch(\n indent: string,\n segment: Extract<FlowSegment, { type: 'branch' }>,\n pages: Record<string, PageDefinition>,\n flow: ComputedFunnelFlow,\n): void {\n const arms = segment.arms\n\n // Compute column widths for each arm\n const colWidths = arms.map((arm) => {\n const maxNameLen = Math.max(\n ...arm.pageKeys.map((key) => {\n const page = pages[key]\n const name = page?.name || key\n const type = page?.type\n // Account for type badge\n const typeLen = type && type !== 'default' ? ` [${type}]`.length : 0\n return name.length + typeLen\n }),\n 8,\n )\n return maxNameLen + 4\n })\n\n // Draw the split line: ├───────┬───────┤\n let splitLine = ''\n for (let a = 0; a < arms.length; a++) {\n const mid = Math.floor(colWidths[a] / 2)\n if (a === 0) {\n splitLine += ' '.repeat(mid) + '├' + H.repeat(colWidths[a] - mid - 1)\n } else if (a === arms.length - 1) {\n splitLine += H.repeat(mid) + '┤' + ' '.repeat(colWidths[a] - mid - 1)\n } else {\n splitLine += H.repeat(mid) + '┬' + H.repeat(colWidths[a] - mid - 1)\n }\n if (a < arms.length - 1) splitLine += H.repeat(3)\n }\n console.log(`${indent}${splitLine}`)\n\n // Draw arm down pipes\n let pipeLine = ''\n for (let a = 0; a < arms.length; a++) {\n const mid = Math.floor(colWidths[a] / 2)\n pipeLine += ' '.repeat(mid) + V + ' '.repeat(colWidths[a] - mid - 1)\n if (a < arms.length - 1) pipeLine += ' '\n }\n console.log(`${indent}${pipeLine}`)\n\n // Draw arm pages row by row\n const maxDepth = Math.max(...arms.map((a) => a.pageKeys.length))\n\n for (let row = 0; row < maxDepth; row++) {\n let line = ''\n for (let a = 0; a < arms.length; a++) {\n const key = arms[a].pageKeys[row]\n const mid = Math.floor(colWidths[a] / 2)\n if (key) {\n const page = pages[key]\n const name = page?.name || key\n const type = page?.type\n const typeBadge = type && type !== 'default' ? ' ' + pc.magenta(`[${type}]`) : ''\n const display = name + typeBadge\n const displayLen = stripAnsi(display).length\n const truncated = displayLen > colWidths[a] - 2\n ? name.slice(0, colWidths[a] - 5) + '...'\n : display\n const truncLen = stripAnsi(truncated).length\n const leftPad = mid - Math.floor(truncLen / 2)\n const rightPad = colWidths[a] - leftPad - truncLen\n line += ' '.repeat(Math.max(0, leftPad)) + pc.bold(truncated) + ' '.repeat(Math.max(0, rightPad))\n } else {\n line += ' '.repeat(colWidths[a])\n }\n if (a < arms.length - 1) line += ' '\n }\n console.log(`${indent}${line}`)\n\n // Draw connector between rows\n if (row < maxDepth - 1) {\n let connector = ''\n for (let a = 0; a < arms.length; a++) {\n const mid = Math.floor(colWidths[a] / 2)\n const hasMore = row + 1 < arms[a].pageKeys.length\n if (hasMore) {\n connector += ' '.repeat(mid) + '▼' + ' '.repeat(colWidths[a] - mid - 1)\n } else {\n connector += ' '.repeat(colWidths[a])\n }\n if (a < arms.length - 1) connector += ' '\n }\n console.log(`${indent}${connector}`)\n }\n }\n\n // Draw the merge line: ├───────┴───────┤\n let mergeLine = ''\n for (let a = 0; a < arms.length; a++) {\n const mid = Math.floor(colWidths[a] / 2)\n if (a === 0) {\n mergeLine += ' '.repeat(mid) + '├' + H.repeat(colWidths[a] - mid - 1)\n } else if (a === arms.length - 1) {\n mergeLine += H.repeat(mid) + '┤' + ' '.repeat(colWidths[a] - mid - 1)\n } else {\n mergeLine += H.repeat(mid) + '┴' + H.repeat(colWidths[a] - mid - 1)\n }\n if (a < arms.length - 1) mergeLine += H.repeat(3)\n }\n console.log(`${indent}${mergeLine}`)\n}\n\nfunction stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, '')\n}\n","import { resolve, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, type AppFunnelConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { generateHtml } from '../vite/html.js'\nimport { formatWarning } from '../lib/errors.js'\nimport { CLIError } from '../lib/errors.js'\n\nconst MAX_TOTAL_SIZE = 2 * 1024 * 1024 // 2MB\nconst MAX_PAGE_SIZE = 500 * 1024 // 500KB\n\n/** UTM query params — always included, no config needed */\nconst BUILTIN_QUERY_PARAMS: Record<string, { type: string }> = {\n utm_source: { type: 'string' },\n utm_medium: { type: 'string' },\n utm_campaign: { type: 'string' },\n utm_content: { type: 'string' },\n utm_term: { type: 'string' },\n}\n\nexport async function buildCommand(): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config + pages\n const s = log.spinner('Analyzing pages...')\n const config = await loadConfig(cwd)\n\n if (!config.projectId) {\n s.stop()\n throw new CLIError(\n 'MISSING_PROJECT_ID',\n 'Missing projectId in appfunnel.config.ts.',\n \"Run 'appfunnel dev' first to select a project, or add projectId manually.\",\n )\n }\n\n if (!config.initialPageKey) {\n s.stop()\n throw new CLIError(\n 'MISSING_INITIAL_PAGE_KEY',\n 'Missing initialPageKey in appfunnel.config.ts.',\n \"Set initialPageKey to the page key (filename without .tsx) of your first page.\",\n )\n }\n\n const pageKeys = scanPages(cwd)\n const pages = await extractPageDefinitions(cwd, pageKeys)\n s.stop()\n\n // 3. Validate routes\n validateRoutes(config, pages, pageKeys)\n\n log.info(`Building ${pageKeys.length} pages...`)\n\n // 4. Build with Vite\n const outDir = resolve(cwd, 'dist')\n const { build } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n // Try to load @tailwindcss/vite from the user's project\n let tailwindPlugin: any = null\n try {\n const { createRequire } = await import('node:module')\n const require = createRequire(join(cwd, 'package.json'))\n const tailwindPath = require.resolve('@tailwindcss/vite')\n const tailwindVite = await import(tailwindPath)\n tailwindPlugin = tailwindVite.default\n } catch {\n // Not installed in the user's project — skip\n }\n\n // Write index.html for Vite to use as entry\n const htmlPath = resolve(cwd, 'index.html')\n const htmlContent = generateHtml(config.name || 'AppFunnel')\n writeFileSync(htmlPath, htmlContent)\n\n try {\n await build({\n root: cwd,\n base: './',\n build: {\n outDir,\n emptyOutDir: true,\n sourcemap: false,\n minify: 'esbuild',\n rollupOptions: {\n output: {\n manualChunks(id) {\n if (id.includes('node_modules/react')) {\n return 'vendor-react'\n }\n if (id.includes('@appfunnel-dev/sdk')) {\n return 'vendor-sdk'\n }\n },\n },\n },\n },\n plugins: [\n react.default(),\n ...(tailwindPlugin ? [tailwindPlugin()] : []),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: false,\n }),\n ],\n css: {\n postcss: cwd,\n },\n logLevel: 'warn',\n })\n } finally {\n // Clean up the temporary index.html\n try {\n const { unlinkSync } = await import('node:fs')\n unlinkSync(htmlPath)\n } catch { /* ignore */ }\n }\n\n // 5. Generate manifest\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Collect asset info\n const assets = collectAssets(outDir)\n const totalSize = assets.reduce((sum, a) => sum + a.size, 0)\n\n const manifest = {\n version: 1,\n buildHash: randomUUID(),\n sdkVersion: getSdkVersion(cwd),\n projectId: config.projectId,\n funnelId: config.funnelId,\n name: config.name,\n initialPageKey: config.initialPageKey,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n responses: config.responses || {},\n queryParams: { ...BUILTIN_QUERY_PARAMS, ...config.queryParams },\n data: config.data || {},\n products: config.products || {},\n defaultLocale: config.defaultLocale,\n assets,\n totalSize,\n }\n\n writeFileSync(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n')\n\n // 6. Print report\n console.log()\n log.success('Build complete')\n console.log()\n console.log(` ${pc.dim('Output:')} dist/`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Size:')} ${formatSize(totalSize)}`)\n console.log()\n\n // Print per-asset sizes\n for (const asset of assets) {\n const sizeStr = formatSize(asset.size)\n const isOver = asset.size > MAX_PAGE_SIZE\n console.log(` ${isOver ? pc.yellow('!') : pc.dim('·')} ${pc.dim(asset.path)} ${isOver ? pc.yellow(sizeStr) : pc.dim(sizeStr)}`)\n }\n console.log()\n\n // Warn on size limits\n if (totalSize > MAX_TOTAL_SIZE) {\n console.log(formatWarning(\n 'BUNDLE_TOO_LARGE',\n `Total bundle size (${formatSize(totalSize)}) exceeds the 2MB limit.`,\n 'This will be rejected on publish. Reduce dependencies or code-split.',\n ))\n console.log()\n }\n\n for (const asset of assets) {\n if (asset.size > MAX_PAGE_SIZE && asset.path.endsWith('.js')) {\n console.log(formatWarning(\n 'PAGE_SIZE',\n `${asset.path} is ${formatSize(asset.size)} (limit: 500KB).`,\n 'Consider reducing dependencies in this page.',\n ))\n }\n }\n}\n\nfunction validateRoutes(\n config: AppFunnelConfig,\n pages: Record<string, { routes?: Array<{ to: string; when?: unknown }> }>,\n pageKeys: string[],\n): void {\n const allPageKeys = new Set(pageKeys)\n\n // Build full set of known variables from all namespaced sections\n const allVariables = new Set<string>()\n if (config.responses) {\n for (const key of Object.keys(config.responses)) {\n allVariables.add(`answers.${key}`)\n }\n }\n if (config.queryParams) {\n for (const key of Object.keys(config.queryParams)) {\n allVariables.add(`query.${key}`)\n }\n }\n if (config.data) {\n for (const key of Object.keys(config.data)) {\n allVariables.add(`data.${key}`)\n }\n }\n\n // Check routes from definePage()\n for (const [pageKey, def] of Object.entries(pages)) {\n if (!def.routes) continue\n for (const route of def.routes) {\n if (!allPageKeys.has(route.to)) {\n throw new CLIError(\n 'INVALID_ROUTE',\n `Page \"${pageKey}\" routes to \"${route.to}\" which does not exist.`,\n `Available pages: ${pageKeys.join(', ')}. Check src/pages/${pageKey}.tsx.`,\n )\n }\n\n // Validate condition variable references\n if (route.when) {\n validateConditionVariables(route.when, pageKey, allVariables)\n }\n }\n }\n}\n\nfunction validateConditionVariables(\n condition: unknown,\n pageKey: string,\n allVariables: Set<string>,\n): void {\n if (!condition || typeof condition !== 'object') return\n\n const cond = condition as Record<string, unknown>\n\n // Simple condition\n if (cond.variable && typeof cond.variable === 'string') {\n // Skip system variables (page.*, device.*, etc.) and user.*\n const prefix = cond.variable.split('.')[0]\n const systemPrefixes = ['page', 'device', 'browser', 'os', 'session', 'system', 'metadata', 'user', 'products', 'card', 'payment', 'stripe', 'subscription']\n if (!systemPrefixes.includes(prefix) && !allVariables.has(cond.variable)) {\n // Suggest the right config section based on the prefix\n const varName = cond.variable.includes('.') ? cond.variable.split('.').slice(1).join('.') : cond.variable\n let hint: string\n if (prefix === 'answers') {\n hint = `Add it to responses in appfunnel.config.ts: responses: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'query') {\n hint = `Add it to queryParams in appfunnel.config.ts: queryParams: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'data') {\n hint = `Add it to data in appfunnel.config.ts: data: { '${varName}': { type: 'string' } }`\n } else {\n hint = `Add it to the appropriate section (responses, queryParams, or data) in appfunnel.config.ts.`\n }\n throw new CLIError(\n 'UNDEFINED_VARIABLE',\n `Route condition in \"${pageKey}\" references variable \"${cond.variable}\" which is not defined.`,\n hint,\n )\n }\n }\n\n // Condition group\n if (Array.isArray(cond.rules)) {\n for (const rule of cond.rules) {\n validateConditionVariables(rule, pageKey, allVariables)\n }\n }\n}\n\nfunction collectAssets(outDir: string): Array<{ path: string; size: number }> {\n const assets: Array<{ path: string; size: number }> = []\n\n function walk(dir: string, prefix: string = ''): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n walk(fullPath, relPath)\n } else if (entry.name !== 'manifest.json' && !entry.name.startsWith('.')) {\n assets.push({ path: relPath, size: statSync(fullPath).size })\n }\n }\n }\n\n walk(outDir)\n return assets\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(2)}MB`\n}\n\nfunction getSdkVersion(cwd: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(cwd, 'node_modules', '@appfunnel-dev', 'sdk', 'package.json'), 'utf-8'))\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n","import { join } from 'node:path'\nimport { readFileSync, writeFileSync } from 'node:fs'\n\n/**\n * Patch appfunnel.config.ts to add a funnelId after the projectId line.\n * Uses simple string replacement — no AST parsing needed.\n */\nexport function patchConfigFunnelId(cwd: string, funnelId: string): void {\n const configPath = join(cwd, 'appfunnel.config.ts')\n let content = readFileSync(configPath, 'utf-8')\n\n // Already has funnelId — don't double-add\n if (content.includes('funnelId')) return\n\n // Insert funnelId after the projectId line\n const patched = content.replace(\n /(projectId:\\s*['\"][^'\"]+['\"],?\\s*\\n)/,\n `$1 funnelId: '${funnelId}',\\n`,\n )\n\n if (patched !== content) {\n writeFileSync(configPath, patched, 'utf-8')\n }\n}\n","import { resolve, join } from 'node:path'\nimport { readFileSync, existsSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { publishBuild } from '../lib/api.js'\nimport { CLIError } from '../lib/errors.js'\nimport { patchConfigFunnelId } from '../lib/config-patch.js'\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.html': 'text/html',\n '.json': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n}\n\nfunction getMimeType(path: string): string {\n const ext = path.substring(path.lastIndexOf('.'))\n return MIME_TYPES[ext] || 'application/octet-stream'\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(2)}MB`\n}\n\nexport async function publishCommand(options?: { promote?: boolean }): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n const creds = requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config\n const config = await loadConfig(cwd)\n\n const projectId = config.projectId\n if (!projectId) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No projectId in appfunnel.config.ts.',\n 'Add projectId to your config. You can find it in the dashboard.',\n )\n }\n\n // 3. Check build output exists\n const outDir = resolve(cwd, 'dist')\n const manifestPath = join(outDir, 'manifest.json')\n\n if (!existsSync(manifestPath)) {\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n 'No build output found.',\n \"Run 'appfunnel build' first.\",\n )\n }\n\n // 4. Read manifest\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'))\n const assets: Array<{ path: string; size: number }> = manifest.assets || []\n\n // 5. Read all asset files\n const s = log.spinner('Preparing assets...')\n const assetPayloads: Array<{ path: string; content: Buffer; contentType: string }> = []\n let totalBytes = 0\n\n for (let i = 0; i < assets.length; i++) {\n const asset = assets[i]\n const fullPath = join(outDir, asset.path)\n if (!existsSync(fullPath)) {\n s.stop()\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n `Build asset missing: ${asset.path}`,\n \"Run 'appfunnel build' to regenerate.\",\n )\n }\n const content = readFileSync(fullPath)\n totalBytes += content.length\n assetPayloads.push({\n path: asset.path,\n content,\n contentType: getMimeType(asset.path),\n })\n s.text = `Preparing assets... ${i + 1}/${assets.length} ${pc.dim(`(${formatSize(totalBytes)})`)}`\n }\n\n // 6. Upload\n s.text = `Uploading ${assets.length} assets ${pc.dim(`(${formatSize(totalBytes)})`)}`\n\n const result = await publishBuild(\n projectId,\n config.funnelId || '',\n manifest,\n assetPayloads,\n { token: creds.token },\n options?.promote,\n )\n\n s.stop()\n\n // 7. If the server created a new funnel, write funnelId back to config\n if (result.created && result.funnelId) {\n patchConfigFunnelId(cwd, result.funnelId)\n log.info(`Funnel created — funnelId added to appfunnel.config.ts`)\n }\n\n // 8. Print result\n console.log()\n log.success(result.activated ? 'Published and activated' : 'Published successfully')\n console.log()\n console.log(` ${pc.dim('Build ID:')} ${result.buildId}`)\n if (result.funnelId && !config.funnelId) {\n console.log(` ${pc.dim('Funnel:')} ${result.funnelId}`)\n }\n console.log(` ${pc.dim('Dashboard:')} ${pc.cyan(result.dashboardUrl)}`)\n console.log(` ${pc.dim('Assets:')} ${assets.length} files ${pc.dim(`(${formatSize(totalBytes)})`)}`)\n if (!result.activated) {\n console.log()\n console.log(` ${pc.dim('Tip:')} Use ${pc.cyan('--promote')} to activate immediately, or promote from the dashboard.`)\n }\n console.log()\n}\n","import { Command } from 'commander'\nimport pc from 'picocolors'\nimport { CLIError, formatError } from './lib/errors.js'\n\nconst program = new Command()\n\nprogram\n .name('appfunnel')\n .description('Build and publish headless AppFunnel projects')\n .version(__CLI_VERSION__)\n\nprogram\n .command('init')\n .argument('[name]', 'Project directory name')\n .description('Create a new AppFunnel project')\n .action(async (name?: string) => {\n const { initCommand } = await import('./commands/init.js')\n await initCommand(name)\n })\n\nprogram\n .command('login')\n .description('Authenticate with AppFunnel')\n .action(async () => {\n const { loginCommand } = await import('./commands/login.js')\n await loginCommand()\n })\n\nprogram\n .command('whoami')\n .description('Show the currently authenticated user')\n .action(async () => {\n const { whoamiCommand } = await import('./commands/whoami.js')\n await whoamiCommand()\n })\n\nprogram\n .command('dev')\n .description('Start the development server')\n .option('-p, --port <port>', 'Port number', '5173')\n .action(async (options: { port: string }) => {\n const { devCommand } = await import('./commands/dev.js')\n await devCommand({ port: parseInt(options.port, 10) })\n })\n\nprogram\n .command('routes')\n .description('Visualize the funnel page flow')\n .action(async () => {\n const { routesCommand } = await import('./commands/routes.js')\n await routesCommand()\n })\n\nprogram\n .command('build')\n .description('Build the funnel for production')\n .action(async () => {\n const { buildCommand } = await import('./commands/build.js')\n await buildCommand()\n })\n\nprogram\n .command('publish')\n .description('Publish the build to AppFunnel')\n .option('--promote', 'Activate the build immediately after publishing')\n .action(async (options: { promote?: boolean }) => {\n const { publishCommand } = await import('./commands/publish.js')\n await publishCommand({ promote: options.promote })\n })\n\n// Global error handler\nprogram.hook('postAction', () => {})\n\nasync function main() {\n try {\n await program.parseAsync(process.argv)\n } catch (err) {\n if (err instanceof CLIError) {\n console.error(formatError(err))\n process.exit(1)\n }\n // Unknown error\n console.error(`${pc.red('ERROR')}: ${err instanceof Error ? err.message : String(err)}`)\n if (err instanceof Error && err.stack) {\n console.error(pc.dim(err.stack))\n }\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":["pc","pc","DEFAULT_API_BASE","error","readFileSync","writeFileSync","join","pc","select","s","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readdirSync","readFileSync","existsSync","join","join","existsSync","resolve","join","existsSync","writeFileSync","mkdirSync","readFileSync","readdirSync","readFileSync","writeFileSync","join","pc","createServer","require","current","globalVisited","pages","pc","resolve","join","randomUUID","readFileSync","writeFileSync","readdirSync","pc","require","getSdkVersion","join","readFileSync","writeFileSync","resolve","join","readFileSync","existsSync","pc","formatSize","pc","initCommand","loginCommand","whoamiCommand","devCommand","routesCommand","buildCommand","publishCommand"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appfunnel",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "CLI for building and publishing headless AppFunnel projects",
5
5
  "type": "module",
6
6
  "bin": {