appfunnel 0.3.0 → 0.5.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
@@ -48,7 +48,6 @@ var init_errors = __esm({
48
48
  });
49
49
 
50
50
  // src/lib/logger.ts
51
- import { readFileSync } from "fs";
52
51
  import pc2 from "picocolors";
53
52
  import ora from "ora";
54
53
  function success(msg) {
@@ -73,12 +72,12 @@ var init_logger = __esm({
73
72
  });
74
73
 
75
74
  // src/lib/auth.ts
76
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
75
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
77
76
  import { join } from "path";
78
77
  import { homedir } from "os";
79
78
  function readCredentials() {
80
79
  try {
81
- const raw = readFileSync2(CREDENTIALS_PATH, "utf-8");
80
+ const raw = readFileSync(CREDENTIALS_PATH, "utf-8");
82
81
  const data = JSON.parse(raw);
83
82
  if (!data.token) return null;
84
83
  return data;
@@ -212,12 +211,12 @@ async function initCommand(name) {
212
211
  publish: "appfunnel publish"
213
212
  },
214
213
  dependencies: {
215
- "@appfunnel-dev/sdk": "^0.3.0",
214
+ "@appfunnel-dev/sdk": "^0.5.0",
216
215
  react: "^18.3.0",
217
216
  "react-dom": "^18.3.0"
218
217
  },
219
218
  devDependencies: {
220
- appfunnel: "^0.3.0",
219
+ appfunnel: "^0.5.0",
221
220
  typescript: "^5.4.0",
222
221
  "@types/react": "^18.2.0",
223
222
  "@types/react-dom": "^18.2.0",
@@ -493,7 +492,7 @@ var init_whoami = __esm({
493
492
  });
494
493
 
495
494
  // src/lib/config.ts
496
- import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
495
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
497
496
  import { join as join3, resolve } from "path";
498
497
  async function loadConfig(cwd) {
499
498
  const configPath = join3(cwd, CONFIG_FILE);
@@ -505,7 +504,7 @@ async function loadConfig(cwd) {
505
504
  );
506
505
  }
507
506
  const { transform } = await import("esbuild");
508
- const raw = readFileSync3(configPath, "utf-8");
507
+ const raw = readFileSync2(configPath, "utf-8");
509
508
  const result = await transform(raw, {
510
509
  loader: "ts",
511
510
  format: "esm",
@@ -537,10 +536,10 @@ var init_config = __esm({
537
536
  });
538
537
 
539
538
  // src/lib/version.ts
540
- import { readFileSync as readFileSync4 } from "fs";
539
+ import { readFileSync as readFileSync3 } from "fs";
541
540
  import { join as join4 } from "path";
542
541
  function checkVersionCompatibility(cwd) {
543
- const cliVersion = getCliVersion();
542
+ const cliVersion = "0.5.0";
544
543
  const sdkVersion = getSdkVersion(cwd);
545
544
  const [cliMajor, cliMinor] = cliVersion.split(".").map(Number);
546
545
  const [sdkMajor, sdkMinor] = sdkVersion.split(".").map(Number);
@@ -552,20 +551,16 @@ function checkVersionCompatibility(cwd) {
552
551
  );
553
552
  }
554
553
  }
555
- function getCliVersion() {
556
- try {
557
- const pkg = JSON.parse(
558
- readFileSync4(new URL("../../package.json", import.meta.url), "utf-8")
559
- );
560
- return pkg.version;
561
- } catch {
562
- return "0.0.0";
563
- }
564
- }
565
554
  function getSdkVersion(cwd) {
566
555
  try {
567
- const pkgPath = join4(cwd, "node_modules", "@appfunnel", "sdk", "package.json");
568
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
556
+ const pkgPath = join4(
557
+ cwd,
558
+ "node_modules",
559
+ "@appfunnel-dev",
560
+ "sdk",
561
+ "package.json"
562
+ );
563
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
569
564
  return pkg.version;
570
565
  } catch {
571
566
  throw new CLIError(
@@ -583,7 +578,7 @@ var init_version = __esm({
583
578
  });
584
579
 
585
580
  // src/extract/pages.ts
586
- import { readdirSync, readFileSync as readFileSync5, existsSync as existsSync3 } from "fs";
581
+ import { readdirSync, readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
587
582
  import { join as join5, basename } from "path";
588
583
  function scanPages(cwd) {
589
584
  const pagesDir = resolvePagesDir(cwd);
@@ -610,7 +605,7 @@ async function extractPageDefinitions(cwd, pageKeys) {
610
605
  const result = {};
611
606
  for (const key of pageKeys) {
612
607
  const filePath = join5(pagesDir, `${key}.tsx`);
613
- const source = readFileSync5(filePath, "utf-8");
608
+ const source = readFileSync4(filePath, "utf-8");
614
609
  const definition = extractDefinePage(ts, source, filePath);
615
610
  if (definition) {
616
611
  result[key] = definition;
@@ -952,7 +947,7 @@ var dev_exports = {};
952
947
  __export(dev_exports, {
953
948
  devCommand: () => devCommand
954
949
  });
955
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
950
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
956
951
  import { join as join8 } from "path";
957
952
  import pc6 from "picocolors";
958
953
  async function devCommand(options) {
@@ -968,7 +963,7 @@ async function devCommand(options) {
968
963
  const projectId = await promptForProject(creds.token);
969
964
  config.projectId = projectId;
970
965
  const configPath = join8(cwd, "appfunnel.config.ts");
971
- const configSource = readFileSync6(configPath, "utf-8");
966
+ const configSource = readFileSync5(configPath, "utf-8");
972
967
  const updated = configSource.replace(
973
968
  /projectId:\s*['"].*?['"]/,
974
969
  `projectId: '${projectId}'`
@@ -1042,7 +1037,7 @@ __export(build_exports, {
1042
1037
  buildCommand: () => buildCommand
1043
1038
  });
1044
1039
  import { resolve as resolve4, join as join9 } from "path";
1045
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, statSync, readdirSync as readdirSync2 } from "fs";
1040
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, statSync, readdirSync as readdirSync2 } from "fs";
1046
1041
  import pc7 from "picocolors";
1047
1042
  async function buildCommand() {
1048
1043
  const cwd = process.cwd();
@@ -1259,7 +1254,7 @@ function formatSize(bytes) {
1259
1254
  }
1260
1255
  function getSdkVersion2(cwd) {
1261
1256
  try {
1262
- const pkg = JSON.parse(readFileSync7(join9(cwd, "node_modules", "@appfunnel", "sdk", "package.json"), "utf-8"));
1257
+ const pkg = JSON.parse(readFileSync6(join9(cwd, "node_modules", "@appfunnel", "sdk", "package.json"), "utf-8"));
1263
1258
  return pkg.version;
1264
1259
  } catch {
1265
1260
  return "0.0.0";
@@ -1376,7 +1371,7 @@ __export(publish_exports, {
1376
1371
  publishCommand: () => publishCommand
1377
1372
  });
1378
1373
  import { resolve as resolve5, join as join10 } from "path";
1379
- import { readFileSync as readFileSync8, existsSync as existsSync5 } from "fs";
1374
+ import { readFileSync as readFileSync7, existsSync as existsSync5 } from "fs";
1380
1375
  import pc8 from "picocolors";
1381
1376
  function getMimeType(path) {
1382
1377
  const ext = path.substring(path.lastIndexOf("."));
@@ -1396,7 +1391,7 @@ async function publishCommand() {
1396
1391
  "Run 'appfunnel build' first."
1397
1392
  );
1398
1393
  }
1399
- const manifest = JSON.parse(readFileSync8(manifestPath, "utf-8"));
1394
+ const manifest = JSON.parse(readFileSync7(manifestPath, "utf-8"));
1400
1395
  const assets = manifest.assets || [];
1401
1396
  const s = spinner("Uploading build...");
1402
1397
  const assetPayloads = [];
@@ -1412,7 +1407,7 @@ async function publishCommand() {
1412
1407
  }
1413
1408
  assetPayloads.push({
1414
1409
  path: asset.path,
1415
- content: readFileSync8(fullPath),
1410
+ content: readFileSync7(fullPath),
1416
1411
  contentType: getMimeType(asset.path)
1417
1412
  });
1418
1413
  }
@@ -1476,21 +1471,10 @@ var init_publish = __esm({
1476
1471
 
1477
1472
  // src/index.ts
1478
1473
  init_errors();
1479
- import { readFileSync as readFileSync9 } from "fs";
1480
1474
  import { Command } from "commander";
1481
1475
  import pc9 from "picocolors";
1482
- function getCliVersion2() {
1483
- try {
1484
- const pkg = JSON.parse(
1485
- readFileSync9(new URL("../package.json", import.meta.url), "utf-8")
1486
- );
1487
- return pkg.version;
1488
- } catch {
1489
- return "0.0.0";
1490
- }
1491
- }
1492
1476
  var program = new Command();
1493
- program.name("appfunnel").description("Build and publish headless AppFunnel projects").version(getCliVersion2());
1477
+ program.name("appfunnel").description("Build and publish headless AppFunnel projects").version("0.5.0");
1494
1478
  program.command("init <name>").description("Create a new AppFunnel project").action(async (name) => {
1495
1479
  const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
1496
1480
  await initCommand2(name);
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/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/api.ts","../src/commands/publish.ts","../src/index.ts"],"sourcesContent":["import pc from 'picocolors'\n\nexport type ErrorCode =\n | 'AUTH_REQUIRED'\n | 'AUTH_EXPIRED'\n | 'CONFIG_NOT_FOUND'\n | 'INVALID_ROUTE'\n | 'UNDEFINED_VARIABLE'\n | 'VERSION_MISMATCH'\n | 'BUILD_NOT_FOUND'\n | 'FUNNEL_NOT_HEADLESS'\n | 'BUNDLE_TOO_LARGE'\n | 'PAGE_SIZE'\n | 'INVALID_PAGE'\n | 'NO_PAGES'\n | 'NO_PROJECTS'\n | 'MISSING_PROJECT_ID'\n | 'API_ERROR'\n | 'PUBLISH_FAILED'\n\nexport class CLIError extends Error {\n code: ErrorCode\n hint?: string\n statusCode?: number\n\n constructor(code: ErrorCode, message: string, hint?: string) {\n super(message)\n this.name = 'CLIError'\n this.code = code\n this.hint = hint\n }\n}\n\nexport function formatError(err: CLIError): string {\n const lines = [\n `${pc.red('ERROR')} ${pc.dim(`[${err.code}]`)}: ${err.message}`,\n ]\n if (err.hint) {\n lines.push(` ${pc.dim('Hint:')} ${err.hint}`)\n }\n return lines.join('\\n')\n}\n\nexport function formatWarning(code: string, message: string, hint?: string): string {\n const lines = [\n `${pc.yellow('WARNING')} ${pc.dim(`[${code}]`)}: ${message}`,\n ]\n if (hint) {\n lines.push(` ${pc.dim('Hint:')} ${hint}`)\n }\n return lines.join('\\n')\n}\n","import { readFileSync } from 'node:fs'\nimport 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' + getVersion())}`)\n console.log()\n}\n\nfunction getVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'),\n )\n return pkg.version\n } catch {\n return '0.0.0'\n }\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 { mkdirSync, writeFileSync, existsSync } 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 { fetchProjects, promptForProject } from '../lib/projects.js'\n\nexport async function initCommand(name: string): Promise<void> {\n\tconst creds = requireAuth()\n\n\tconst dir = join(process.cwd(), name)\n\n\tif (existsSync(dir)) {\n\t\tlog.error(`Directory '${name}' already exists.`)\n\t\tprocess.exit(1)\n\t}\n\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\tconst s = log.spinner(`Creating ${name}...`)\n\n\t// Create directory structure\n\tmkdirSync(join(dir, 'src', 'pages'), { recursive: true })\n\tmkdirSync(join(dir, 'src', 'components'), { recursive: true })\n\tmkdirSync(join(dir, 'locales'), { recursive: true })\n\n\t// package.json\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': '^0.3.0',\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: '^0.3.0',\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\t// tsconfig.json\n\twriteFileSync(\n\t\tjoin(dir, 'tsconfig.json'),\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\ttarget: 'ES2020',\n\t\t\t\t\tmodule: 'ESNext',\n\t\t\t\t\tmoduleResolution: 'bundler',\n\t\t\t\t\tjsx: 'react-jsx',\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tesModuleInterop: true,\n\t\t\t\t\tskipLibCheck: true,\n\t\t\t\t\tpaths: {\n\t\t\t\t\t\t'@/*': ['./src/*'],\n\t\t\t\t\t},\n\t\t\t\t\tbaseUrl: '.',\n\t\t\t\t},\n\t\t\t\tinclude: ['src'],\n\t\t\t},\n\t\t\tnull,\n\t\t\t2\n\t\t) + '\\n'\n\t)\n\n\t// tailwind + css\n\twriteFileSync(join(dir, 'src', 'app.css'), `@import \"tailwindcss\";\\n`)\n\n\t// appfunnel.config.ts\n\twriteFileSync(\n\t\tjoin(dir, 'appfunnel.config.ts'),\n\t\t`import { defineConfig } from '@appfunnel-dev/sdk'\n\nexport default defineConfig({\n projectId: '${projectId}',\n name: '${name}',\n defaultLocale: 'en',\n\n responses: {\n goal: { type: 'string' },\n },\n\n products: {\n items: [],\n },\n})\n`\n\t)\n\n\t// funnel.tsx\n\twriteFileSync(\n\t\tjoin(dir, 'src', 'funnel.tsx'),\n\t\t`import './app.css'\n\nexport default function Funnel({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"min-h-screen\">\n {children}\n </div>\n )\n}\n`\n\t)\n\n\t// Example page\n\twriteFileSync(\n\t\tjoin(dir, 'src', 'pages', 'index.tsx'),\n\t\t`import { definePage, useResponse, useNavigation } from '@appfunnel-dev/sdk'\n\nexport const page = definePage({\n name: 'Landing',\n type: 'default',\n routes: [],\n})\n\nexport default function Landing() {\n const [goal, setGoal] = useResponse<string>('goal')\n const { goToNextPage } = useNavigation()\n\n return (\n <div className=\"flex min-h-screen items-center justify-center p-4\">\n <div className=\"w-full max-w-md space-y-6\">\n <h1 className=\"text-3xl font-bold text-center\">Welcome</h1>\n <input\n type=\"text\"\n value={goal}\n onChange={(e) => setGoal(e.target.value)}\n placeholder=\"What's your goal?\"\n className=\"w-full rounded-xl border p-4 text-lg\"\n />\n <button\n onClick={goToNextPage}\n disabled={!goal.trim()}\n className=\"w-full rounded-xl bg-blue-600 py-4 text-lg font-bold text-white disabled:opacity-50\"\n >\n Continue\n </button>\n </div>\n </div>\n )\n}\n`\n\t)\n\n\t// locales/en.json\n\twriteFileSync(\n\t\tjoin(dir, 'locales', 'en.json'),\n\t\tJSON.stringify({ welcome: 'Welcome' }, null, 2) + '\\n'\n\t)\n\n\t// .gitignore\n\twriteFileSync(\n\t\tjoin(dir, '.gitignore'),\n\t\t`node_modules\ndist\n.appfunnel\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 initialPage?: 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 }>\n defaultId?: string\n }\n settings?: { apiBaseUrl?: string }\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 version: 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 const cliVersion = getCliVersion()\n const sdkVersion = getSdkVersion(cwd)\n\n const [cliMajor, cliMinor] = cliVersion.split('.').map(Number)\n const [sdkMajor, sdkMinor] = sdkVersion.split('.').map(Number)\n\n if (cliMajor !== sdkMajor || cliMinor !== sdkMinor) {\n throw new CLIError(\n 'VERSION_MISMATCH',\n `CLI version ${cliVersion} requires @appfunnel-dev/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,\n \"Run 'npm install @appfunnel-dev/sdk@latest' to update.\",\n )\n }\n}\n\nfunction getCliVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'),\n ) as PackageJson\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n\nfunction getSdkVersion(cwd: string): string {\n try {\n const pkgPath = join(cwd, 'node_modules', '@appfunnel', 'sdk', 'package.json')\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as PackageJson\n return pkg.version\n } catch {\n throw new CLIError(\n 'VERSION_MISMATCH',\n '@appfunnel-dev/sdk is not installed.',\n \"Run 'npm install @appfunnel-dev/sdk' to install it.\",\n )\n }\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 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}\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 pushState\n * - Lazy-loads page components\n */\nexport function generateEntrySource(options: EntryOptions): string {\n const { config, pages, pagesDir, funnelTsxPath, isDev } = 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 const trackingCode = isDev\n ? `\n// Dev mode: mock tracking — log events to console\nconst originalFetch = globalThis.fetch;\nglobalThis.__APPFUNNEL_DEV__ = true;\n`\n : ''\n\n return `\nimport { StrictMode, lazy, Suspense, useState, useEffect, useCallback } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { FunnelProvider } from '@appfunnel-dev/sdk/internal'\nimport FunnelWrapper from '${funnelTsxPath.replace(/\\\\/g, '/')}'\n\n${trackingCode}\n\nconst pages = {\n${pageImports}\n}\n\nconst config = ${JSON.stringify(fullConfig, null, 2)}\n\nconst slugToKey = ${JSON.stringify(slugMap)}\nconst keyToSlug = ${JSON.stringify(\n Object.fromEntries(Object.entries(slugMap).map(([s, k]) => [k, s])),\n )}\n\nfunction getInitialPage() {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n return slugToKey[path] || '${config.initialPage || pageKeys[0] || 'index'}'\n}\n\nfunction App() {\n const [currentPage, setCurrentPage] = useState(getInitialPage)\n\n useEffect(() => {\n const handlePopState = () => {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n const pageKey = slugToKey[path]\n if (pageKey && pageKey !== currentPage) {\n setCurrentPage(pageKey)\n }\n }\n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [currentPage])\n\n // Expose navigation to FunnelProvider's router\n useEffect(() => {\n window.__APPFUNNEL_NAVIGATE__ = (pageKey) => {\n setCurrentPage(pageKey)\n const slug = keyToSlug[pageKey] || pageKey\n window.history.pushState(null, '', '/' + slug)\n }\n return () => { delete window.__APPFUNNEL_NAVIGATE__ }\n }, [])\n\n const PageComponent = pages[currentPage]\n\n if (!PageComponent) {\n return <div style={{ padding: '2rem', color: 'red' }}>Page not found: {currentPage}</div>\n }\n\n return (\n <FunnelProvider\n config={config}\n initialPage={currentPage}\n apiBaseUrl={${isDev ? \"''\" : \"config.settings?.apiBaseUrl || ''\"}}\n >\n <FunnelWrapper>\n <Suspense fallback={null}>\n <PageComponent />\n </Suspense>\n </FunnelWrapper>\n </FunnelProvider>\n )\n}\n\ncreateRoot(document.getElementById('root')).render(\n <StrictMode>\n <App />\n </StrictMode>\n)\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 } 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\nconst VIRTUAL_HTML_ID = '@appfunnel/index.html'\n\ninterface PluginOptions {\n cwd: string\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n isDev: boolean\n onPagesChange?: () => Promise<void>\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\n let server: ViteDevServer | undefined\n\n function getEntrySource(): string {\n return generateEntrySource({\n config,\n pages,\n pagesDir,\n funnelTsxPath,\n isDev,\n })\n }\n\n return {\n name: 'appfunnel',\n\n config() {\n return {\n resolve: {\n alias: {\n '@': resolve(cwd, 'src'),\n },\n },\n // Ensure we can import .tsx files\n esbuild: {\n jsx: 'automatic',\n },\n optimizeDeps: {\n include: ['react', 'react-dom', 'react/jsx-runtime'],\n },\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n return getEntrySource()\n }\n return null\n },\n\n configureServer(devServer) {\n server = devServer\n\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 // Invalidate the virtual module and trigger full reload\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 // SPA fallback middleware — serve index.html for all routes\n return () => {\n devServer.middlewares.use((req, res, next) => {\n // Skip Vite internal routes and static assets\n if (\n req.url?.startsWith('/@') ||\n req.url?.startsWith('/node_modules') ||\n req.url?.startsWith('/src') ||\n req.url?.includes('.')\n ) {\n return next()\n }\n\n // Serve the HTML shell for all other routes\n const html = generateHtml(config.name || 'AppFunnel')\n devServer.transformIndexHtml(req.url || '/', html).then((transformed) => {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n }).catch(next)\n })\n }\n },\n\n // For production build: inject the HTML as the input\n transformIndexHtml(html) {\n return html\n },\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { resolve, 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'\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 const updated = configSource.replace(\n /projectId:\\s*['\"].*?['\"]/,\n `projectId: '${projectId}'`,\n )\n if (updated !== configSource) {\n writeFileSync(configPath, updated)\n log.success(`Updated projectId in appfunnel.config.ts`)\n } else {\n // If regex didn't match (e.g. projectId field doesn't exist), warn\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. Start Vite dev server\n const { createServer } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n const server = await createServer({\n root: cwd,\n server: {\n port,\n strictPort: false,\n },\n plugins: [\n react.default(),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: true,\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 { 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 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, '.appfunnel')\n const { build } = await import('vite')\n const react = await import('@vitejs/plugin-react')\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 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 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 sdkVersion: getSdkVersion(cwd),\n projectId: config.projectId,\n funnelId: config.funnelId,\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 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:')} .appfunnel/`)\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.filter(a => a.path.endsWith('.js'))) {\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', 'sdk', 'package.json'), 'utf-8'))\n return pkg.version\n } catch {\n return '0.0.0'\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/**\n * Create a new headless funnel under a project.\n */\nexport async function createHeadlessFunnel(\n\tprojectId: string,\n\tname: string,\n\toptions: ApiOptions\n): Promise<{ funnelId: string; identifier: string }> {\n\tconst response = await apiFetch(`/project/${projectId}/headless/funnels`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ name }),\n\t})\n\n\treturn (await response.json()) as { funnelId: string; identifier: string }\n}\n\n/**\n * Publish a headless build.\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): Promise<{ buildId: string; url: string }> {\n\t// Use multipart form data for assets\n\tconst formData = new FormData()\n\tformData.set('manifest', JSON.stringify(manifest))\n\tformData.set('funnelId', funnelId)\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; url: 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'Create a new headless funnel from the dashboard, or remove funnelId from config.'\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 { 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'\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\nexport async function publishCommand(): 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 // 3. Check build output exists\n const outDir = resolve(cwd, '.appfunnel')\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('Uploading build...')\n const assetPayloads: Array<{ path: string; content: Buffer; contentType: string }> = []\n\n for (const asset of assets) {\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 assetPayloads.push({\n path: asset.path,\n content: readFileSync(fullPath),\n contentType: getMimeType(asset.path),\n })\n }\n\n // 6. Publish\n const projectId = config.projectId\n const funnelId = config.funnelId\n\n if (!projectId) {\n s.stop()\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 if (!funnelId) {\n s.stop()\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No funnelId in appfunnel.config.ts.',\n 'Add funnelId to your config, or create a new funnel from the dashboard.',\n )\n }\n\n const result = await publishBuild(\n projectId,\n funnelId,\n manifest,\n assetPayloads,\n { token: creds.token },\n )\n\n s.stop()\n\n // 7. Print result\n console.log()\n log.success('Published successfully')\n console.log()\n console.log(` ${pc.dim('Build ID:')} ${result.buildId}`)\n console.log(` ${pc.dim('URL:')} ${pc.cyan(result.url)}`)\n console.log(` ${pc.dim('Assets:')} ${assets.length} files`)\n console.log()\n}\n","import { readFileSync } from 'node:fs'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { CLIError, formatError } from './lib/errors.js'\n\nfunction getCliVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf-8'),\n )\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n\nconst program = new Command()\n\nprogram\n .name('appfunnel')\n .description('Build and publish headless AppFunnel projects')\n .version(getCliVersion())\n\nprogram\n .command('init <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 .action(async () => {\n const { publishCommand } = await import('./commands/publish.js')\n await publishCommand()\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","readFileSync","pc","mkdirSync","writeFileSync","join","pc","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readFileSync","existsSync","join","join","resolve","join","existsSync","readFileSync","writeFileSync","join","pc","createServer","resolve","join","readFileSync","writeFileSync","readdirSync","pc","getSdkVersion","DEFAULT_API_BASE","error","resolve","join","readFileSync","existsSync","pc","readFileSync","pc","getCliVersion","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/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/api.ts","../src/commands/publish.ts","../src/index.ts"],"sourcesContent":["import pc from 'picocolors'\n\nexport type ErrorCode =\n | 'AUTH_REQUIRED'\n | 'AUTH_EXPIRED'\n | 'CONFIG_NOT_FOUND'\n | 'INVALID_ROUTE'\n | 'UNDEFINED_VARIABLE'\n | 'VERSION_MISMATCH'\n | 'BUILD_NOT_FOUND'\n | 'FUNNEL_NOT_HEADLESS'\n | 'BUNDLE_TOO_LARGE'\n | 'PAGE_SIZE'\n | 'INVALID_PAGE'\n | 'NO_PAGES'\n | 'NO_PROJECTS'\n | 'MISSING_PROJECT_ID'\n | 'API_ERROR'\n | 'PUBLISH_FAILED'\n\nexport class CLIError extends Error {\n code: ErrorCode\n hint?: string\n statusCode?: number\n\n constructor(code: ErrorCode, message: string, hint?: string) {\n super(message)\n this.name = 'CLIError'\n this.code = code\n this.hint = hint\n }\n}\n\nexport function formatError(err: CLIError): string {\n const lines = [\n `${pc.red('ERROR')} ${pc.dim(`[${err.code}]`)}: ${err.message}`,\n ]\n if (err.hint) {\n lines.push(` ${pc.dim('Hint:')} ${err.hint}`)\n }\n return lines.join('\\n')\n}\n\nexport function formatWarning(code: string, message: string, hint?: string): string {\n const lines = [\n `${pc.yellow('WARNING')} ${pc.dim(`[${code}]`)}: ${message}`,\n ]\n if (hint) {\n lines.push(` ${pc.dim('Hint:')} ${hint}`)\n }\n return 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 { mkdirSync, writeFileSync, existsSync } 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 { fetchProjects, promptForProject } from '../lib/projects.js'\n\nexport async function initCommand(name: string): Promise<void> {\n\tconst creds = requireAuth()\n\n\tconst dir = join(process.cwd(), name)\n\n\tif (existsSync(dir)) {\n\t\tlog.error(`Directory '${name}' already exists.`)\n\t\tprocess.exit(1)\n\t}\n\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\tconst s = log.spinner(`Creating ${name}...`)\n\n\t// Create directory structure\n\tmkdirSync(join(dir, 'src', 'pages'), { recursive: true })\n\tmkdirSync(join(dir, 'src', 'components'), { recursive: true })\n\tmkdirSync(join(dir, 'locales'), { recursive: true })\n\n\t// package.json\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': '^0.5.0',\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: '^0.5.0',\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\t// tsconfig.json\n\twriteFileSync(\n\t\tjoin(dir, 'tsconfig.json'),\n\t\tJSON.stringify(\n\t\t\t{\n\t\t\t\tcompilerOptions: {\n\t\t\t\t\ttarget: 'ES2020',\n\t\t\t\t\tmodule: 'ESNext',\n\t\t\t\t\tmoduleResolution: 'bundler',\n\t\t\t\t\tjsx: 'react-jsx',\n\t\t\t\t\tstrict: true,\n\t\t\t\t\tesModuleInterop: true,\n\t\t\t\t\tskipLibCheck: true,\n\t\t\t\t\tpaths: {\n\t\t\t\t\t\t'@/*': ['./src/*'],\n\t\t\t\t\t},\n\t\t\t\t\tbaseUrl: '.',\n\t\t\t\t},\n\t\t\t\tinclude: ['src'],\n\t\t\t},\n\t\t\tnull,\n\t\t\t2\n\t\t) + '\\n'\n\t)\n\n\t// tailwind + css\n\twriteFileSync(join(dir, 'src', 'app.css'), `@import \"tailwindcss\";\\n`)\n\n\t// appfunnel.config.ts\n\twriteFileSync(\n\t\tjoin(dir, 'appfunnel.config.ts'),\n\t\t`import { defineConfig } from '@appfunnel-dev/sdk'\n\nexport default defineConfig({\n projectId: '${projectId}',\n name: '${name}',\n defaultLocale: 'en',\n\n responses: {\n goal: { type: 'string' },\n },\n\n products: {\n items: [],\n },\n})\n`\n\t)\n\n\t// funnel.tsx\n\twriteFileSync(\n\t\tjoin(dir, 'src', 'funnel.tsx'),\n\t\t`import './app.css'\n\nexport default function Funnel({ children }: { children: React.ReactNode }) {\n return (\n <div className=\"min-h-screen\">\n {children}\n </div>\n )\n}\n`\n\t)\n\n\t// Example page\n\twriteFileSync(\n\t\tjoin(dir, 'src', 'pages', 'index.tsx'),\n\t\t`import { definePage, useResponse, useNavigation } from '@appfunnel-dev/sdk'\n\nexport const page = definePage({\n name: 'Landing',\n type: 'default',\n routes: [],\n})\n\nexport default function Landing() {\n const [goal, setGoal] = useResponse<string>('goal')\n const { goToNextPage } = useNavigation()\n\n return (\n <div className=\"flex min-h-screen items-center justify-center p-4\">\n <div className=\"w-full max-w-md space-y-6\">\n <h1 className=\"text-3xl font-bold text-center\">Welcome</h1>\n <input\n type=\"text\"\n value={goal}\n onChange={(e) => setGoal(e.target.value)}\n placeholder=\"What's your goal?\"\n className=\"w-full rounded-xl border p-4 text-lg\"\n />\n <button\n onClick={goToNextPage}\n disabled={!goal.trim()}\n className=\"w-full rounded-xl bg-blue-600 py-4 text-lg font-bold text-white disabled:opacity-50\"\n >\n Continue\n </button>\n </div>\n </div>\n )\n}\n`\n\t)\n\n\t// locales/en.json\n\twriteFileSync(\n\t\tjoin(dir, 'locales', 'en.json'),\n\t\tJSON.stringify({ welcome: 'Welcome' }, null, 2) + '\\n'\n\t)\n\n\t// .gitignore\n\twriteFileSync(\n\t\tjoin(dir, '.gitignore'),\n\t\t`node_modules\ndist\n.appfunnel\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 initialPage?: 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 }>\n defaultId?: string\n }\n settings?: { apiBaseUrl?: string }\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 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}\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 pushState\n * - Lazy-loads page components\n */\nexport function generateEntrySource(options: EntryOptions): string {\n const { config, pages, pagesDir, funnelTsxPath, isDev } = 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 const trackingCode = isDev\n ? `\n// Dev mode: mock tracking — log events to console\nconst originalFetch = globalThis.fetch;\nglobalThis.__APPFUNNEL_DEV__ = true;\n`\n : ''\n\n return `\nimport { StrictMode, lazy, Suspense, useState, useEffect, useCallback } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { FunnelProvider } from '@appfunnel-dev/sdk/internal'\nimport FunnelWrapper from '${funnelTsxPath.replace(/\\\\/g, '/')}'\n\n${trackingCode}\n\nconst pages = {\n${pageImports}\n}\n\nconst config = ${JSON.stringify(fullConfig, null, 2)}\n\nconst slugToKey = ${JSON.stringify(slugMap)}\nconst keyToSlug = ${JSON.stringify(\n Object.fromEntries(Object.entries(slugMap).map(([s, k]) => [k, s])),\n )}\n\nfunction getInitialPage() {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n return slugToKey[path] || '${config.initialPage || pageKeys[0] || 'index'}'\n}\n\nfunction App() {\n const [currentPage, setCurrentPage] = useState(getInitialPage)\n\n useEffect(() => {\n const handlePopState = () => {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n const pageKey = slugToKey[path]\n if (pageKey && pageKey !== currentPage) {\n setCurrentPage(pageKey)\n }\n }\n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [currentPage])\n\n // Expose navigation to FunnelProvider's router\n useEffect(() => {\n window.__APPFUNNEL_NAVIGATE__ = (pageKey) => {\n setCurrentPage(pageKey)\n const slug = keyToSlug[pageKey] || pageKey\n window.history.pushState(null, '', '/' + slug)\n }\n return () => { delete window.__APPFUNNEL_NAVIGATE__ }\n }, [])\n\n const PageComponent = pages[currentPage]\n\n if (!PageComponent) {\n return <div style={{ padding: '2rem', color: 'red' }}>Page not found: {currentPage}</div>\n }\n\n return (\n <FunnelProvider\n config={config}\n initialPage={currentPage}\n apiBaseUrl={${isDev ? \"''\" : \"config.settings?.apiBaseUrl || ''\"}}\n >\n <FunnelWrapper>\n <Suspense fallback={null}>\n <PageComponent />\n </Suspense>\n </FunnelWrapper>\n </FunnelProvider>\n )\n}\n\ncreateRoot(document.getElementById('root')).render(\n <StrictMode>\n <App />\n </StrictMode>\n)\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 } 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\nconst VIRTUAL_HTML_ID = '@appfunnel/index.html'\n\ninterface PluginOptions {\n cwd: string\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n isDev: boolean\n onPagesChange?: () => Promise<void>\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\n let server: ViteDevServer | undefined\n\n function getEntrySource(): string {\n return generateEntrySource({\n config,\n pages,\n pagesDir,\n funnelTsxPath,\n isDev,\n })\n }\n\n return {\n name: 'appfunnel',\n\n config() {\n return {\n resolve: {\n alias: {\n '@': resolve(cwd, 'src'),\n },\n },\n // Ensure we can import .tsx files\n esbuild: {\n jsx: 'automatic',\n },\n optimizeDeps: {\n include: ['react', 'react-dom', 'react/jsx-runtime'],\n },\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n return getEntrySource()\n }\n return null\n },\n\n configureServer(devServer) {\n server = devServer\n\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 // Invalidate the virtual module and trigger full reload\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 // SPA fallback middleware — serve index.html for all routes\n return () => {\n devServer.middlewares.use((req, res, next) => {\n // Skip Vite internal routes and static assets\n if (\n req.url?.startsWith('/@') ||\n req.url?.startsWith('/node_modules') ||\n req.url?.startsWith('/src') ||\n req.url?.includes('.')\n ) {\n return next()\n }\n\n // Serve the HTML shell for all other routes\n const html = generateHtml(config.name || 'AppFunnel')\n devServer.transformIndexHtml(req.url || '/', html).then((transformed) => {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n }).catch(next)\n })\n }\n },\n\n // For production build: inject the HTML as the input\n transformIndexHtml(html) {\n return html\n },\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { resolve, 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'\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 const updated = configSource.replace(\n /projectId:\\s*['\"].*?['\"]/,\n `projectId: '${projectId}'`,\n )\n if (updated !== configSource) {\n writeFileSync(configPath, updated)\n log.success(`Updated projectId in appfunnel.config.ts`)\n } else {\n // If regex didn't match (e.g. projectId field doesn't exist), warn\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. Start Vite dev server\n const { createServer } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n const server = await createServer({\n root: cwd,\n server: {\n port,\n strictPort: false,\n },\n plugins: [\n react.default(),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: true,\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 { 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 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, '.appfunnel')\n const { build } = await import('vite')\n const react = await import('@vitejs/plugin-react')\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 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 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 sdkVersion: getSdkVersion(cwd),\n projectId: config.projectId,\n funnelId: config.funnelId,\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 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:')} .appfunnel/`)\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.filter(a => a.path.endsWith('.js'))) {\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', 'sdk', 'package.json'), 'utf-8'))\n return pkg.version\n } catch {\n return '0.0.0'\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/**\n * Create a new headless funnel under a project.\n */\nexport async function createHeadlessFunnel(\n\tprojectId: string,\n\tname: string,\n\toptions: ApiOptions\n): Promise<{ funnelId: string; identifier: string }> {\n\tconst response = await apiFetch(`/project/${projectId}/headless/funnels`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ name }),\n\t})\n\n\treturn (await response.json()) as { funnelId: string; identifier: string }\n}\n\n/**\n * Publish a headless build.\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): Promise<{ buildId: string; url: string }> {\n\t// Use multipart form data for assets\n\tconst formData = new FormData()\n\tformData.set('manifest', JSON.stringify(manifest))\n\tformData.set('funnelId', funnelId)\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; url: 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'Create a new headless funnel from the dashboard, or remove funnelId from config.'\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 { 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'\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\nexport async function publishCommand(): 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 // 3. Check build output exists\n const outDir = resolve(cwd, '.appfunnel')\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('Uploading build...')\n const assetPayloads: Array<{ path: string; content: Buffer; contentType: string }> = []\n\n for (const asset of assets) {\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 assetPayloads.push({\n path: asset.path,\n content: readFileSync(fullPath),\n contentType: getMimeType(asset.path),\n })\n }\n\n // 6. Publish\n const projectId = config.projectId\n const funnelId = config.funnelId\n\n if (!projectId) {\n s.stop()\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 if (!funnelId) {\n s.stop()\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No funnelId in appfunnel.config.ts.',\n 'Add funnelId to your config, or create a new funnel from the dashboard.',\n )\n }\n\n const result = await publishBuild(\n projectId,\n funnelId,\n manifest,\n assetPayloads,\n { token: creds.token },\n )\n\n s.stop()\n\n // 7. Print result\n console.log()\n log.success('Published successfully')\n console.log()\n console.log(` ${pc.dim('Build ID:')} ${result.buildId}`)\n console.log(` ${pc.dim('URL:')} ${pc.cyan(result.url)}`)\n console.log(` ${pc.dim('Assets:')} ${assets.length} files`)\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 <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 .action(async () => {\n const { publishCommand } = await import('./commands/publish.js')\n await publishCommand()\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","mkdirSync","writeFileSync","join","pc","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readFileSync","existsSync","join","join","resolve","join","existsSync","readFileSync","writeFileSync","join","pc","createServer","resolve","join","readFileSync","writeFileSync","readdirSync","pc","getSdkVersion","DEFAULT_API_BASE","error","resolve","join","readFileSync","existsSync","pc","pc","initCommand","loginCommand","whoamiCommand","devCommand","buildCommand","publishCommand"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appfunnel",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI for building and publishing headless AppFunnel projects",
5
5
  "type": "module",
6
6
  "bin": {