appfunnel 0.2.0 → 0.4.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 +135 -82
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
4
|
var __esm = (fn, res) => function __init() {
|
|
@@ -122,13 +121,7 @@ var init_auth = __esm({
|
|
|
122
121
|
}
|
|
123
122
|
});
|
|
124
123
|
|
|
125
|
-
// src/
|
|
126
|
-
var init_exports = {};
|
|
127
|
-
__export(init_exports, {
|
|
128
|
-
initCommand: () => initCommand
|
|
129
|
-
});
|
|
130
|
-
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync } from "fs";
|
|
131
|
-
import { join as join2 } from "path";
|
|
124
|
+
// src/lib/projects.ts
|
|
132
125
|
import pc3 from "picocolors";
|
|
133
126
|
import select from "@inquirer/select";
|
|
134
127
|
async function fetchProjects(token) {
|
|
@@ -144,17 +137,11 @@ async function fetchProjects(token) {
|
|
|
144
137
|
const body = await response.json();
|
|
145
138
|
return body.data;
|
|
146
139
|
}
|
|
147
|
-
async function
|
|
148
|
-
const
|
|
149
|
-
const dir = join2(process.cwd(), name);
|
|
150
|
-
if (existsSync(dir)) {
|
|
151
|
-
error(`Directory '${name}' already exists.`);
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
const spin = spinner("Fetching projects\u2026");
|
|
140
|
+
async function promptForProject(token) {
|
|
141
|
+
const spin = spinner("Fetching projects...");
|
|
155
142
|
let projects;
|
|
156
143
|
try {
|
|
157
|
-
projects = await fetchProjects(
|
|
144
|
+
projects = await fetchProjects(token);
|
|
158
145
|
} catch (err) {
|
|
159
146
|
spin.stop();
|
|
160
147
|
if (err instanceof CLIError) throw err;
|
|
@@ -171,13 +158,41 @@ async function initCommand(name) {
|
|
|
171
158
|
"Create a project at https://appfunnel.net first."
|
|
172
159
|
);
|
|
173
160
|
}
|
|
174
|
-
|
|
161
|
+
return select({
|
|
175
162
|
message: "Select a project",
|
|
176
163
|
choices: projects.map((p) => ({
|
|
177
164
|
name: `${p.name} ${pc3.dim(`(${p.id})`)}`,
|
|
178
165
|
value: p.id
|
|
179
166
|
}))
|
|
180
167
|
});
|
|
168
|
+
}
|
|
169
|
+
var DEFAULT_API_BASE;
|
|
170
|
+
var init_projects = __esm({
|
|
171
|
+
"src/lib/projects.ts"() {
|
|
172
|
+
"use strict";
|
|
173
|
+
init_logger();
|
|
174
|
+
init_errors();
|
|
175
|
+
DEFAULT_API_BASE = "https://api.appfunnel.net";
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// src/commands/init.ts
|
|
180
|
+
var init_exports = {};
|
|
181
|
+
__export(init_exports, {
|
|
182
|
+
initCommand: () => initCommand
|
|
183
|
+
});
|
|
184
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync } from "fs";
|
|
185
|
+
import { join as join2 } from "path";
|
|
186
|
+
import pc4 from "picocolors";
|
|
187
|
+
async function initCommand(name) {
|
|
188
|
+
const creds = requireAuth();
|
|
189
|
+
const dir = join2(process.cwd(), name);
|
|
190
|
+
if (existsSync(dir)) {
|
|
191
|
+
error(`Directory '${name}' already exists.`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
const projectId = await promptForProject(creds.token);
|
|
195
|
+
const projects = await fetchProjects(creds.token);
|
|
181
196
|
const project = projects.find((p) => p.id === projectId);
|
|
182
197
|
const s = spinner(`Creating ${name}...`);
|
|
183
198
|
mkdirSync2(join2(dir, "src", "pages"), { recursive: true });
|
|
@@ -197,12 +212,12 @@ async function initCommand(name) {
|
|
|
197
212
|
publish: "appfunnel publish"
|
|
198
213
|
},
|
|
199
214
|
dependencies: {
|
|
200
|
-
"@appfunnel-dev/sdk": "^0.
|
|
215
|
+
"@appfunnel-dev/sdk": "^0.3.0",
|
|
201
216
|
react: "^18.3.0",
|
|
202
217
|
"react-dom": "^18.3.0"
|
|
203
218
|
},
|
|
204
219
|
devDependencies: {
|
|
205
|
-
appfunnel: "^0.
|
|
220
|
+
appfunnel: "^0.3.0",
|
|
206
221
|
typescript: "^5.4.0",
|
|
207
222
|
"@types/react": "^18.2.0",
|
|
208
223
|
"@types/react-dom": "^18.2.0",
|
|
@@ -254,12 +269,6 @@ export default defineConfig({
|
|
|
254
269
|
goal: { type: 'string' },
|
|
255
270
|
},
|
|
256
271
|
|
|
257
|
-
queryParams: {
|
|
258
|
-
utm_source: { type: 'string' },
|
|
259
|
-
utm_medium: { type: 'string' },
|
|
260
|
-
utm_campaign: { type: 'string' },
|
|
261
|
-
},
|
|
262
|
-
|
|
263
272
|
products: {
|
|
264
273
|
items: [],
|
|
265
274
|
},
|
|
@@ -330,21 +339,19 @@ dist
|
|
|
330
339
|
);
|
|
331
340
|
s.stop();
|
|
332
341
|
console.log();
|
|
333
|
-
success(`Created ${
|
|
342
|
+
success(`Created ${pc4.bold(name)} for project ${pc4.bold(project.name)}`);
|
|
334
343
|
console.log();
|
|
335
|
-
console.log(` ${
|
|
336
|
-
console.log(` ${
|
|
337
|
-
console.log(` ${
|
|
344
|
+
console.log(` ${pc4.dim("cd")} ${name}`);
|
|
345
|
+
console.log(` ${pc4.dim("npm install")}`);
|
|
346
|
+
console.log(` ${pc4.dim("appfunnel dev")}`);
|
|
338
347
|
console.log();
|
|
339
348
|
}
|
|
340
|
-
var DEFAULT_API_BASE;
|
|
341
349
|
var init_init = __esm({
|
|
342
350
|
"src/commands/init.ts"() {
|
|
343
351
|
"use strict";
|
|
344
352
|
init_logger();
|
|
345
353
|
init_auth();
|
|
346
|
-
|
|
347
|
-
DEFAULT_API_BASE = "https://api.appfunnel.net";
|
|
354
|
+
init_projects();
|
|
348
355
|
}
|
|
349
356
|
});
|
|
350
357
|
|
|
@@ -358,7 +365,7 @@ import { randomUUID } from "crypto";
|
|
|
358
365
|
import open from "open";
|
|
359
366
|
async function loginCommand() {
|
|
360
367
|
const state = randomUUID();
|
|
361
|
-
return new Promise((
|
|
368
|
+
return new Promise((resolve6, reject) => {
|
|
362
369
|
const server = createServer((req, res) => {
|
|
363
370
|
const url = new URL(req.url || "/", `http://localhost`);
|
|
364
371
|
if (url.pathname !== "/callback") {
|
|
@@ -397,7 +404,7 @@ async function loginCommand() {
|
|
|
397
404
|
spinner2.stop();
|
|
398
405
|
success(`Logged in as ${email || userId}`);
|
|
399
406
|
server.close();
|
|
400
|
-
|
|
407
|
+
resolve6();
|
|
401
408
|
});
|
|
402
409
|
server.listen(0, "127.0.0.1", () => {
|
|
403
410
|
const addr = server.address();
|
|
@@ -438,7 +445,7 @@ var whoami_exports = {};
|
|
|
438
445
|
__export(whoami_exports, {
|
|
439
446
|
whoamiCommand: () => whoamiCommand
|
|
440
447
|
});
|
|
441
|
-
import
|
|
448
|
+
import pc5 from "picocolors";
|
|
442
449
|
async function whoamiCommand() {
|
|
443
450
|
const creds = requireAuth();
|
|
444
451
|
const spin = spinner("Verifying credentials\u2026");
|
|
@@ -459,11 +466,11 @@ async function whoamiCommand() {
|
|
|
459
466
|
}
|
|
460
467
|
const user = await response.json();
|
|
461
468
|
spin.stop();
|
|
462
|
-
success(`Logged in as ${
|
|
463
|
-
info(`User ID: ${
|
|
469
|
+
success(`Logged in as ${pc5.bold(user.email)}`);
|
|
470
|
+
info(`User ID: ${pc5.dim(user.id)}`);
|
|
464
471
|
if (creds.expiresAt) {
|
|
465
472
|
const expiresAt = new Date(creds.expiresAt);
|
|
466
|
-
info(`Token expires: ${
|
|
473
|
+
info(`Token expires: ${pc5.dim(expiresAt.toLocaleString())}`);
|
|
467
474
|
}
|
|
468
475
|
} catch (err) {
|
|
469
476
|
spin.stop();
|
|
@@ -508,10 +515,10 @@ async function loadConfig(cwd) {
|
|
|
508
515
|
const dataUri = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
|
|
509
516
|
const mod = await import(dataUri);
|
|
510
517
|
const config = mod.default;
|
|
511
|
-
if (!config
|
|
518
|
+
if (!config) {
|
|
512
519
|
throw new CLIError(
|
|
513
520
|
"CONFIG_NOT_FOUND",
|
|
514
|
-
`Invalid config in ${CONFIG_FILE}
|
|
521
|
+
`Invalid config in ${CONFIG_FILE}.`,
|
|
515
522
|
"Make sure your config exports a valid object with defineConfig()."
|
|
516
523
|
);
|
|
517
524
|
}
|
|
@@ -548,7 +555,10 @@ function checkVersionCompatibility(cwd) {
|
|
|
548
555
|
function getCliVersion() {
|
|
549
556
|
try {
|
|
550
557
|
const pkg = JSON.parse(
|
|
551
|
-
readFileSync4(
|
|
558
|
+
readFileSync4(
|
|
559
|
+
new URL("../../package.json", import.meta.url),
|
|
560
|
+
"utf-8"
|
|
561
|
+
)
|
|
552
562
|
);
|
|
553
563
|
return pkg.version;
|
|
554
564
|
} catch {
|
|
@@ -557,7 +567,13 @@ function getCliVersion() {
|
|
|
557
567
|
}
|
|
558
568
|
function getSdkVersion(cwd) {
|
|
559
569
|
try {
|
|
560
|
-
const pkgPath = join4(
|
|
570
|
+
const pkgPath = join4(
|
|
571
|
+
cwd,
|
|
572
|
+
"node_modules",
|
|
573
|
+
"@appfunnel-dev",
|
|
574
|
+
"sdk",
|
|
575
|
+
"package.json"
|
|
576
|
+
);
|
|
561
577
|
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
562
578
|
return pkg.version;
|
|
563
579
|
} catch {
|
|
@@ -945,17 +961,38 @@ var dev_exports = {};
|
|
|
945
961
|
__export(dev_exports, {
|
|
946
962
|
devCommand: () => devCommand
|
|
947
963
|
});
|
|
948
|
-
import
|
|
964
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
965
|
+
import { join as join8 } from "path";
|
|
966
|
+
import pc6 from "picocolors";
|
|
949
967
|
async function devCommand(options) {
|
|
950
968
|
const cwd = process.cwd();
|
|
951
969
|
const port = options.port || 5173;
|
|
952
|
-
requireAuth();
|
|
970
|
+
const creds = requireAuth();
|
|
953
971
|
checkVersionCompatibility(cwd);
|
|
954
972
|
const s = spinner("Loading config...");
|
|
955
973
|
const config = await loadConfig(cwd);
|
|
974
|
+
s.stop();
|
|
975
|
+
if (!config.projectId) {
|
|
976
|
+
info("No projectId found in appfunnel.config.ts");
|
|
977
|
+
const projectId = await promptForProject(creds.token);
|
|
978
|
+
config.projectId = projectId;
|
|
979
|
+
const configPath = join8(cwd, "appfunnel.config.ts");
|
|
980
|
+
const configSource = readFileSync6(configPath, "utf-8");
|
|
981
|
+
const updated = configSource.replace(
|
|
982
|
+
/projectId:\s*['"].*?['"]/,
|
|
983
|
+
`projectId: '${projectId}'`
|
|
984
|
+
);
|
|
985
|
+
if (updated !== configSource) {
|
|
986
|
+
writeFileSync3(configPath, updated);
|
|
987
|
+
success(`Updated projectId in appfunnel.config.ts`);
|
|
988
|
+
} else {
|
|
989
|
+
warn(`Could not auto-update appfunnel.config.ts \u2014 add projectId: '${projectId}' manually.`);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
const s2 = spinner("Scanning pages...");
|
|
956
993
|
let pageKeys = scanPages(cwd);
|
|
957
994
|
let pages = await extractPageDefinitions(cwd, pageKeys);
|
|
958
|
-
|
|
995
|
+
s2.stop();
|
|
959
996
|
info(`Found ${pageKeys.length} pages: ${pageKeys.join(", ")}`);
|
|
960
997
|
const { createServer: createServer2 } = await import("vite");
|
|
961
998
|
const react = await import("@vitejs/plugin-react");
|
|
@@ -986,13 +1023,13 @@ async function devCommand(options) {
|
|
|
986
1023
|
await server.listen();
|
|
987
1024
|
const address = server.resolvedUrls?.local?.[0] || `http://localhost:${port}`;
|
|
988
1025
|
console.log();
|
|
989
|
-
console.log(` ${
|
|
1026
|
+
console.log(` ${pc6.bold(config.name || "AppFunnel")} dev server`);
|
|
990
1027
|
console.log();
|
|
991
|
-
console.log(` ${
|
|
992
|
-
console.log(` ${
|
|
993
|
-
console.log(` ${
|
|
1028
|
+
console.log(` ${pc6.dim("Local:")} ${pc6.cyan(address)}`);
|
|
1029
|
+
console.log(` ${pc6.dim("Pages:")} ${pageKeys.length}`);
|
|
1030
|
+
console.log(` ${pc6.dim("Tracking:")} ${pc6.yellow("mocked (console)")}`);
|
|
994
1031
|
console.log();
|
|
995
|
-
console.log(` ${
|
|
1032
|
+
console.log(` ${pc6.dim("Press")} ${pc6.bold("Ctrl+C")} ${pc6.dim("to stop")}`);
|
|
996
1033
|
console.log();
|
|
997
1034
|
}
|
|
998
1035
|
var init_dev = __esm({
|
|
@@ -1004,6 +1041,7 @@ var init_dev = __esm({
|
|
|
1004
1041
|
init_version();
|
|
1005
1042
|
init_pages();
|
|
1006
1043
|
init_plugin();
|
|
1044
|
+
init_projects();
|
|
1007
1045
|
}
|
|
1008
1046
|
});
|
|
1009
1047
|
|
|
@@ -1012,26 +1050,34 @@ var build_exports = {};
|
|
|
1012
1050
|
__export(build_exports, {
|
|
1013
1051
|
buildCommand: () => buildCommand
|
|
1014
1052
|
});
|
|
1015
|
-
import { resolve as
|
|
1016
|
-
import { readFileSync as
|
|
1017
|
-
import
|
|
1053
|
+
import { resolve as resolve4, join as join9 } from "path";
|
|
1054
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, statSync, readdirSync as readdirSync2 } from "fs";
|
|
1055
|
+
import pc7 from "picocolors";
|
|
1018
1056
|
async function buildCommand() {
|
|
1019
1057
|
const cwd = process.cwd();
|
|
1020
1058
|
requireAuth();
|
|
1021
1059
|
checkVersionCompatibility(cwd);
|
|
1022
1060
|
const s = spinner("Analyzing pages...");
|
|
1023
1061
|
const config = await loadConfig(cwd);
|
|
1062
|
+
if (!config.projectId) {
|
|
1063
|
+
s.stop();
|
|
1064
|
+
throw new CLIError(
|
|
1065
|
+
"MISSING_PROJECT_ID",
|
|
1066
|
+
"Missing projectId in appfunnel.config.ts.",
|
|
1067
|
+
"Run 'appfunnel dev' first to select a project, or add projectId manually."
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1024
1070
|
const pageKeys = scanPages(cwd);
|
|
1025
1071
|
const pages = await extractPageDefinitions(cwd, pageKeys);
|
|
1026
1072
|
s.stop();
|
|
1027
1073
|
validateRoutes(config, pages, pageKeys);
|
|
1028
1074
|
info(`Building ${pageKeys.length} pages...`);
|
|
1029
|
-
const outDir =
|
|
1075
|
+
const outDir = resolve4(cwd, ".appfunnel");
|
|
1030
1076
|
const { build } = await import("vite");
|
|
1031
1077
|
const react = await import("@vitejs/plugin-react");
|
|
1032
|
-
const htmlPath =
|
|
1078
|
+
const htmlPath = resolve4(cwd, "index.html");
|
|
1033
1079
|
const htmlContent = generateHtml(config.name || "AppFunnel");
|
|
1034
|
-
|
|
1080
|
+
writeFileSync4(htmlPath, htmlContent);
|
|
1035
1081
|
try {
|
|
1036
1082
|
await build({
|
|
1037
1083
|
root: cwd,
|
|
@@ -1096,24 +1142,24 @@ async function buildCommand() {
|
|
|
1096
1142
|
pages: { ...config.pages, ...mergedPages },
|
|
1097
1143
|
routes: { ...config.routes, ...mergedRoutes },
|
|
1098
1144
|
responses: config.responses || {},
|
|
1099
|
-
queryParams: config.queryParams
|
|
1145
|
+
queryParams: { ...BUILTIN_QUERY_PARAMS, ...config.queryParams },
|
|
1100
1146
|
data: config.data || {},
|
|
1101
1147
|
defaultLocale: config.defaultLocale,
|
|
1102
1148
|
assets,
|
|
1103
1149
|
totalSize
|
|
1104
1150
|
};
|
|
1105
|
-
|
|
1151
|
+
writeFileSync4(join9(outDir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
1106
1152
|
console.log();
|
|
1107
1153
|
success("Build complete");
|
|
1108
1154
|
console.log();
|
|
1109
|
-
console.log(` ${
|
|
1110
|
-
console.log(` ${
|
|
1111
|
-
console.log(` ${
|
|
1155
|
+
console.log(` ${pc7.dim("Output:")} .appfunnel/`);
|
|
1156
|
+
console.log(` ${pc7.dim("Pages:")} ${pageKeys.length}`);
|
|
1157
|
+
console.log(` ${pc7.dim("Size:")} ${formatSize(totalSize)}`);
|
|
1112
1158
|
console.log();
|
|
1113
1159
|
for (const asset of assets.filter((a) => a.path.endsWith(".js"))) {
|
|
1114
1160
|
const sizeStr = formatSize(asset.size);
|
|
1115
1161
|
const isOver = asset.size > MAX_PAGE_SIZE;
|
|
1116
|
-
console.log(` ${isOver ?
|
|
1162
|
+
console.log(` ${isOver ? pc7.yellow("!") : pc7.dim("\xB7")} ${pc7.dim(asset.path)} ${isOver ? pc7.yellow(sizeStr) : pc7.dim(sizeStr)}`);
|
|
1117
1163
|
}
|
|
1118
1164
|
console.log();
|
|
1119
1165
|
if (totalSize > MAX_TOTAL_SIZE) {
|
|
@@ -1204,7 +1250,7 @@ function collectAssets(outDir) {
|
|
|
1204
1250
|
function walk(dir, prefix = "") {
|
|
1205
1251
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
1206
1252
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1207
|
-
const fullPath =
|
|
1253
|
+
const fullPath = join9(dir, entry.name);
|
|
1208
1254
|
if (entry.isDirectory()) {
|
|
1209
1255
|
walk(fullPath, relPath);
|
|
1210
1256
|
} else if (entry.name !== "manifest.json" && !entry.name.startsWith(".")) {
|
|
@@ -1222,13 +1268,13 @@ function formatSize(bytes) {
|
|
|
1222
1268
|
}
|
|
1223
1269
|
function getSdkVersion2(cwd) {
|
|
1224
1270
|
try {
|
|
1225
|
-
const pkg = JSON.parse(
|
|
1271
|
+
const pkg = JSON.parse(readFileSync7(join9(cwd, "node_modules", "@appfunnel", "sdk", "package.json"), "utf-8"));
|
|
1226
1272
|
return pkg.version;
|
|
1227
1273
|
} catch {
|
|
1228
1274
|
return "0.0.0";
|
|
1229
1275
|
}
|
|
1230
1276
|
}
|
|
1231
|
-
var MAX_TOTAL_SIZE, MAX_PAGE_SIZE;
|
|
1277
|
+
var MAX_TOTAL_SIZE, MAX_PAGE_SIZE, BUILTIN_QUERY_PARAMS;
|
|
1232
1278
|
var init_build = __esm({
|
|
1233
1279
|
"src/commands/build.ts"() {
|
|
1234
1280
|
"use strict";
|
|
@@ -1243,6 +1289,13 @@ var init_build = __esm({
|
|
|
1243
1289
|
init_errors();
|
|
1244
1290
|
MAX_TOTAL_SIZE = 2 * 1024 * 1024;
|
|
1245
1291
|
MAX_PAGE_SIZE = 500 * 1024;
|
|
1292
|
+
BUILTIN_QUERY_PARAMS = {
|
|
1293
|
+
utm_source: { type: "string" },
|
|
1294
|
+
utm_medium: { type: "string" },
|
|
1295
|
+
utm_campaign: { type: "string" },
|
|
1296
|
+
utm_content: { type: "string" },
|
|
1297
|
+
utm_term: { type: "string" }
|
|
1298
|
+
};
|
|
1246
1299
|
}
|
|
1247
1300
|
});
|
|
1248
1301
|
|
|
@@ -1331,9 +1384,9 @@ var publish_exports = {};
|
|
|
1331
1384
|
__export(publish_exports, {
|
|
1332
1385
|
publishCommand: () => publishCommand
|
|
1333
1386
|
});
|
|
1334
|
-
import { resolve as
|
|
1335
|
-
import { readFileSync as
|
|
1336
|
-
import
|
|
1387
|
+
import { resolve as resolve5, join as join10 } from "path";
|
|
1388
|
+
import { readFileSync as readFileSync8, existsSync as existsSync5 } from "fs";
|
|
1389
|
+
import pc8 from "picocolors";
|
|
1337
1390
|
function getMimeType(path) {
|
|
1338
1391
|
const ext = path.substring(path.lastIndexOf("."));
|
|
1339
1392
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -1343,8 +1396,8 @@ async function publishCommand() {
|
|
|
1343
1396
|
const creds = requireAuth();
|
|
1344
1397
|
checkVersionCompatibility(cwd);
|
|
1345
1398
|
const config = await loadConfig(cwd);
|
|
1346
|
-
const outDir =
|
|
1347
|
-
const manifestPath =
|
|
1399
|
+
const outDir = resolve5(cwd, ".appfunnel");
|
|
1400
|
+
const manifestPath = join10(outDir, "manifest.json");
|
|
1348
1401
|
if (!existsSync5(manifestPath)) {
|
|
1349
1402
|
throw new CLIError(
|
|
1350
1403
|
"BUILD_NOT_FOUND",
|
|
@@ -1352,12 +1405,12 @@ async function publishCommand() {
|
|
|
1352
1405
|
"Run 'appfunnel build' first."
|
|
1353
1406
|
);
|
|
1354
1407
|
}
|
|
1355
|
-
const manifest = JSON.parse(
|
|
1408
|
+
const manifest = JSON.parse(readFileSync8(manifestPath, "utf-8"));
|
|
1356
1409
|
const assets = manifest.assets || [];
|
|
1357
1410
|
const s = spinner("Uploading build...");
|
|
1358
1411
|
const assetPayloads = [];
|
|
1359
1412
|
for (const asset of assets) {
|
|
1360
|
-
const fullPath =
|
|
1413
|
+
const fullPath = join10(outDir, asset.path);
|
|
1361
1414
|
if (!existsSync5(fullPath)) {
|
|
1362
1415
|
s.stop();
|
|
1363
1416
|
throw new CLIError(
|
|
@@ -1368,7 +1421,7 @@ async function publishCommand() {
|
|
|
1368
1421
|
}
|
|
1369
1422
|
assetPayloads.push({
|
|
1370
1423
|
path: asset.path,
|
|
1371
|
-
content:
|
|
1424
|
+
content: readFileSync8(fullPath),
|
|
1372
1425
|
contentType: getMimeType(asset.path)
|
|
1373
1426
|
});
|
|
1374
1427
|
}
|
|
@@ -1401,9 +1454,9 @@ async function publishCommand() {
|
|
|
1401
1454
|
console.log();
|
|
1402
1455
|
success("Published successfully");
|
|
1403
1456
|
console.log();
|
|
1404
|
-
console.log(` ${
|
|
1405
|
-
console.log(` ${
|
|
1406
|
-
console.log(` ${
|
|
1457
|
+
console.log(` ${pc8.dim("Build ID:")} ${result.buildId}`);
|
|
1458
|
+
console.log(` ${pc8.dim("URL:")} ${pc8.cyan(result.url)}`);
|
|
1459
|
+
console.log(` ${pc8.dim("Assets:")} ${assets.length} files`);
|
|
1407
1460
|
console.log();
|
|
1408
1461
|
}
|
|
1409
1462
|
var MIME_TYPES;
|
|
@@ -1432,13 +1485,13 @@ var init_publish = __esm({
|
|
|
1432
1485
|
|
|
1433
1486
|
// src/index.ts
|
|
1434
1487
|
init_errors();
|
|
1435
|
-
import { readFileSync as
|
|
1488
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
1436
1489
|
import { Command } from "commander";
|
|
1437
|
-
import
|
|
1490
|
+
import pc9 from "picocolors";
|
|
1438
1491
|
function getCliVersion2() {
|
|
1439
1492
|
try {
|
|
1440
1493
|
const pkg = JSON.parse(
|
|
1441
|
-
|
|
1494
|
+
readFileSync9(new URL("../package.json", import.meta.url), "utf-8")
|
|
1442
1495
|
);
|
|
1443
1496
|
return pkg.version;
|
|
1444
1497
|
} catch {
|
|
@@ -1481,9 +1534,9 @@ async function main() {
|
|
|
1481
1534
|
console.error(formatError(err));
|
|
1482
1535
|
process.exit(1);
|
|
1483
1536
|
}
|
|
1484
|
-
console.error(`${
|
|
1537
|
+
console.error(`${pc9.red("ERROR")}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1485
1538
|
if (err instanceof Error && err.stack) {
|
|
1486
|
-
console.error(
|
|
1539
|
+
console.error(pc9.dim(err.stack));
|
|
1487
1540
|
}
|
|
1488
1541
|
process.exit(1);
|
|
1489
1542
|
}
|
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/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 | '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 { mkdirSync, writeFileSync, existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport pc from 'picocolors'\nimport select from '@inquirer/select'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { CLIError } from '../lib/errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\ninterface Project {\n\tid: string\n\tname: string\n\trole: string\n}\n\nasync function fetchProjects(token: string): Promise<Project[]> {\n\tconst response = await fetch(`${DEFAULT_API_BASE}/user/projects`, {\n\t\theaders: {\n\t\t\tAuthorization: token,\n\t\t\t'Content-Type': 'application/json',\n\t\t},\n\t})\n\n\tif (!response.ok) {\n\t\tthrow new CLIError('API_ERROR', 'Failed to fetch projects.')\n\t}\n\n\tconst body = (await response.json()) as { data: Project[] }\n\treturn body.data\n}\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 spin = log.spinner('Fetching projects…')\n\tlet projects: Project[]\n\ttry {\n\t\tprojects = await fetchProjects(creds.token)\n\t} catch (err) {\n\t\tspin.stop()\n\t\tif (err instanceof CLIError) throw err\n\t\tthrow new CLIError(\n\t\t\t'API_ERROR',\n\t\t\t'Failed to reach the API. Check your internet connection.'\n\t\t)\n\t}\n\tspin.stop()\n\n\tif (projects.length === 0) {\n\t\tthrow new CLIError(\n\t\t\t'NO_PROJECTS',\n\t\t\t'No projects found.',\n\t\t\t'Create a project at https://appfunnel.net first.'\n\t\t)\n\t}\n\n\tconst projectId = await select({\n\t\tmessage: 'Select a project',\n\t\tchoices: projects.map((p) => ({\n\t\t\tname: `${p.name} ${pc.dim(`(${p.id})`)}`,\n\t\t\tvalue: p.id,\n\t\t})),\n\t})\n\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.1.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.1.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 queryParams: {\n utm_source: { type: 'string' },\n utm_medium: { type: 'string' },\n utm_campaign: { 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 || !config.projectId) {\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n `Invalid config in ${CONFIG_FILE}: missing projectId.`,\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 { resolve } 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'\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 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\n // 4. Scan and extract pages\n let pageKeys = scanPages(cwd)\n let pages = await extractPageDefinitions(cwd, pageKeys)\n s.stop()\n\n log.info(`Found ${pageKeys.length} pages: ${pageKeys.join(', ')}`)\n\n // 5. 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\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 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: 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","#!/usr/bin/env node\nimport { 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","mkdirSync","writeFileSync","join","pc","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readFileSync","existsSync","join","join","resolve","join","existsSync","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 { 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\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 = getCliVersion()\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 getCliVersion(): string {\n\ttry {\n\t\tconst pkg = JSON.parse(\n\t\t\treadFileSync(\n\t\t\t\tnew URL('../../package.json', import.meta.url),\n\t\t\t\t'utf-8'\n\t\t\t)\n\t\t) as PackageJson\n\t\treturn pkg.version\n\t} catch {\n\t\treturn '0.0.0'\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 { 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"]}
|