appfunnel 0.1.0 → 0.3.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 +167 -92
- 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/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",
|
|
@@ -243,19 +258,17 @@ async function initCommand(name) {
|
|
|
243
258
|
`);
|
|
244
259
|
writeFileSync2(
|
|
245
260
|
join2(dir, "appfunnel.config.ts"),
|
|
246
|
-
`import { defineConfig } from '@appfunnel/sdk'
|
|
261
|
+
`import { defineConfig } from '@appfunnel-dev/sdk'
|
|
247
262
|
|
|
248
263
|
export default defineConfig({
|
|
249
264
|
projectId: '${projectId}',
|
|
250
265
|
name: '${name}',
|
|
251
266
|
defaultLocale: 'en',
|
|
252
267
|
|
|
253
|
-
|
|
254
|
-
|
|
268
|
+
responses: {
|
|
269
|
+
goal: { type: 'string' },
|
|
255
270
|
},
|
|
256
271
|
|
|
257
|
-
queryParams: ['utm_source', 'utm_medium', 'utm_campaign'],
|
|
258
|
-
|
|
259
272
|
products: {
|
|
260
273
|
items: [],
|
|
261
274
|
},
|
|
@@ -277,7 +290,7 @@ export default function Funnel({ children }: { children: React.ReactNode }) {
|
|
|
277
290
|
);
|
|
278
291
|
writeFileSync2(
|
|
279
292
|
join2(dir, "src", "pages", "index.tsx"),
|
|
280
|
-
`import { definePage,
|
|
293
|
+
`import { definePage, useResponse, useNavigation } from '@appfunnel-dev/sdk'
|
|
281
294
|
|
|
282
295
|
export const page = definePage({
|
|
283
296
|
name: 'Landing',
|
|
@@ -286,7 +299,7 @@ export const page = definePage({
|
|
|
286
299
|
})
|
|
287
300
|
|
|
288
301
|
export default function Landing() {
|
|
289
|
-
const [goal, setGoal] =
|
|
302
|
+
const [goal, setGoal] = useResponse<string>('goal')
|
|
290
303
|
const { goToNextPage } = useNavigation()
|
|
291
304
|
|
|
292
305
|
return (
|
|
@@ -326,21 +339,19 @@ dist
|
|
|
326
339
|
);
|
|
327
340
|
s.stop();
|
|
328
341
|
console.log();
|
|
329
|
-
success(`Created ${
|
|
342
|
+
success(`Created ${pc4.bold(name)} for project ${pc4.bold(project.name)}`);
|
|
330
343
|
console.log();
|
|
331
|
-
console.log(` ${
|
|
332
|
-
console.log(` ${
|
|
333
|
-
console.log(` ${
|
|
344
|
+
console.log(` ${pc4.dim("cd")} ${name}`);
|
|
345
|
+
console.log(` ${pc4.dim("npm install")}`);
|
|
346
|
+
console.log(` ${pc4.dim("appfunnel dev")}`);
|
|
334
347
|
console.log();
|
|
335
348
|
}
|
|
336
|
-
var DEFAULT_API_BASE;
|
|
337
349
|
var init_init = __esm({
|
|
338
350
|
"src/commands/init.ts"() {
|
|
339
351
|
"use strict";
|
|
340
352
|
init_logger();
|
|
341
353
|
init_auth();
|
|
342
|
-
|
|
343
|
-
DEFAULT_API_BASE = "https://api.appfunnel.net";
|
|
354
|
+
init_projects();
|
|
344
355
|
}
|
|
345
356
|
});
|
|
346
357
|
|
|
@@ -354,7 +365,7 @@ import { randomUUID } from "crypto";
|
|
|
354
365
|
import open from "open";
|
|
355
366
|
async function loginCommand() {
|
|
356
367
|
const state = randomUUID();
|
|
357
|
-
return new Promise((
|
|
368
|
+
return new Promise((resolve6, reject) => {
|
|
358
369
|
const server = createServer((req, res) => {
|
|
359
370
|
const url = new URL(req.url || "/", `http://localhost`);
|
|
360
371
|
if (url.pathname !== "/callback") {
|
|
@@ -393,7 +404,7 @@ async function loginCommand() {
|
|
|
393
404
|
spinner2.stop();
|
|
394
405
|
success(`Logged in as ${email || userId}`);
|
|
395
406
|
server.close();
|
|
396
|
-
|
|
407
|
+
resolve6();
|
|
397
408
|
});
|
|
398
409
|
server.listen(0, "127.0.0.1", () => {
|
|
399
410
|
const addr = server.address();
|
|
@@ -434,7 +445,7 @@ var whoami_exports = {};
|
|
|
434
445
|
__export(whoami_exports, {
|
|
435
446
|
whoamiCommand: () => whoamiCommand
|
|
436
447
|
});
|
|
437
|
-
import
|
|
448
|
+
import pc5 from "picocolors";
|
|
438
449
|
async function whoamiCommand() {
|
|
439
450
|
const creds = requireAuth();
|
|
440
451
|
const spin = spinner("Verifying credentials\u2026");
|
|
@@ -455,11 +466,11 @@ async function whoamiCommand() {
|
|
|
455
466
|
}
|
|
456
467
|
const user = await response.json();
|
|
457
468
|
spin.stop();
|
|
458
|
-
success(`Logged in as ${
|
|
459
|
-
info(`User ID: ${
|
|
469
|
+
success(`Logged in as ${pc5.bold(user.email)}`);
|
|
470
|
+
info(`User ID: ${pc5.dim(user.id)}`);
|
|
460
471
|
if (creds.expiresAt) {
|
|
461
472
|
const expiresAt = new Date(creds.expiresAt);
|
|
462
|
-
info(`Token expires: ${
|
|
473
|
+
info(`Token expires: ${pc5.dim(expiresAt.toLocaleString())}`);
|
|
463
474
|
}
|
|
464
475
|
} catch (err) {
|
|
465
476
|
spin.stop();
|
|
@@ -500,14 +511,14 @@ async function loadConfig(cwd) {
|
|
|
500
511
|
format: "esm",
|
|
501
512
|
target: "es2022"
|
|
502
513
|
});
|
|
503
|
-
const code = result.code.replace(/import\s*\{[^}]*\}\s*from\s*['"]@appfunnel\/sdk['"]\s*;?/g, "").replace(/\bdefineConfig\s*\(/g, "(");
|
|
514
|
+
const code = result.code.replace(/import\s*\{[^}]*\}\s*from\s*['"]@appfunnel-dev\/sdk['"]\s*;?/g, "").replace(/\bdefineConfig\s*\(/g, "(");
|
|
504
515
|
const dataUri = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
|
|
505
516
|
const mod = await import(dataUri);
|
|
506
517
|
const config = mod.default;
|
|
507
|
-
if (!config
|
|
518
|
+
if (!config) {
|
|
508
519
|
throw new CLIError(
|
|
509
520
|
"CONFIG_NOT_FOUND",
|
|
510
|
-
`Invalid config in ${CONFIG_FILE}
|
|
521
|
+
`Invalid config in ${CONFIG_FILE}.`,
|
|
511
522
|
"Make sure your config exports a valid object with defineConfig()."
|
|
512
523
|
);
|
|
513
524
|
}
|
|
@@ -536,8 +547,8 @@ function checkVersionCompatibility(cwd) {
|
|
|
536
547
|
if (cliMajor !== sdkMajor || cliMinor !== sdkMinor) {
|
|
537
548
|
throw new CLIError(
|
|
538
549
|
"VERSION_MISMATCH",
|
|
539
|
-
`CLI version ${cliVersion} requires @appfunnel/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,
|
|
540
|
-
"Run 'npm install @appfunnel/sdk@latest' to update."
|
|
550
|
+
`CLI version ${cliVersion} requires @appfunnel-dev/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,
|
|
551
|
+
"Run 'npm install @appfunnel-dev/sdk@latest' to update."
|
|
541
552
|
);
|
|
542
553
|
}
|
|
543
554
|
}
|
|
@@ -559,8 +570,8 @@ function getSdkVersion(cwd) {
|
|
|
559
570
|
} catch {
|
|
560
571
|
throw new CLIError(
|
|
561
572
|
"VERSION_MISMATCH",
|
|
562
|
-
"@appfunnel/sdk is not installed.",
|
|
563
|
-
"Run 'npm install @appfunnel/sdk' to install it."
|
|
573
|
+
"@appfunnel-dev/sdk is not installed.",
|
|
574
|
+
"Run 'npm install @appfunnel-dev/sdk' to install it."
|
|
564
575
|
);
|
|
565
576
|
}
|
|
566
577
|
}
|
|
@@ -723,7 +734,7 @@ globalThis.__APPFUNNEL_DEV__ = true;
|
|
|
723
734
|
return `
|
|
724
735
|
import { StrictMode, lazy, Suspense, useState, useEffect, useCallback } from 'react'
|
|
725
736
|
import { createRoot } from 'react-dom/client'
|
|
726
|
-
import { FunnelProvider } from '@appfunnel/sdk/internal'
|
|
737
|
+
import { FunnelProvider } from '@appfunnel-dev/sdk/internal'
|
|
727
738
|
import FunnelWrapper from '${funnelTsxPath.replace(/\\/g, "/")}'
|
|
728
739
|
|
|
729
740
|
${trackingCode}
|
|
@@ -941,17 +952,38 @@ var dev_exports = {};
|
|
|
941
952
|
__export(dev_exports, {
|
|
942
953
|
devCommand: () => devCommand
|
|
943
954
|
});
|
|
944
|
-
import
|
|
955
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
956
|
+
import { join as join8 } from "path";
|
|
957
|
+
import pc6 from "picocolors";
|
|
945
958
|
async function devCommand(options) {
|
|
946
959
|
const cwd = process.cwd();
|
|
947
960
|
const port = options.port || 5173;
|
|
948
|
-
requireAuth();
|
|
961
|
+
const creds = requireAuth();
|
|
949
962
|
checkVersionCompatibility(cwd);
|
|
950
963
|
const s = spinner("Loading config...");
|
|
951
964
|
const config = await loadConfig(cwd);
|
|
965
|
+
s.stop();
|
|
966
|
+
if (!config.projectId) {
|
|
967
|
+
info("No projectId found in appfunnel.config.ts");
|
|
968
|
+
const projectId = await promptForProject(creds.token);
|
|
969
|
+
config.projectId = projectId;
|
|
970
|
+
const configPath = join8(cwd, "appfunnel.config.ts");
|
|
971
|
+
const configSource = readFileSync6(configPath, "utf-8");
|
|
972
|
+
const updated = configSource.replace(
|
|
973
|
+
/projectId:\s*['"].*?['"]/,
|
|
974
|
+
`projectId: '${projectId}'`
|
|
975
|
+
);
|
|
976
|
+
if (updated !== configSource) {
|
|
977
|
+
writeFileSync3(configPath, updated);
|
|
978
|
+
success(`Updated projectId in appfunnel.config.ts`);
|
|
979
|
+
} else {
|
|
980
|
+
warn(`Could not auto-update appfunnel.config.ts \u2014 add projectId: '${projectId}' manually.`);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const s2 = spinner("Scanning pages...");
|
|
952
984
|
let pageKeys = scanPages(cwd);
|
|
953
985
|
let pages = await extractPageDefinitions(cwd, pageKeys);
|
|
954
|
-
|
|
986
|
+
s2.stop();
|
|
955
987
|
info(`Found ${pageKeys.length} pages: ${pageKeys.join(", ")}`);
|
|
956
988
|
const { createServer: createServer2 } = await import("vite");
|
|
957
989
|
const react = await import("@vitejs/plugin-react");
|
|
@@ -982,13 +1014,13 @@ async function devCommand(options) {
|
|
|
982
1014
|
await server.listen();
|
|
983
1015
|
const address = server.resolvedUrls?.local?.[0] || `http://localhost:${port}`;
|
|
984
1016
|
console.log();
|
|
985
|
-
console.log(` ${
|
|
1017
|
+
console.log(` ${pc6.bold(config.name || "AppFunnel")} dev server`);
|
|
986
1018
|
console.log();
|
|
987
|
-
console.log(` ${
|
|
988
|
-
console.log(` ${
|
|
989
|
-
console.log(` ${
|
|
1019
|
+
console.log(` ${pc6.dim("Local:")} ${pc6.cyan(address)}`);
|
|
1020
|
+
console.log(` ${pc6.dim("Pages:")} ${pageKeys.length}`);
|
|
1021
|
+
console.log(` ${pc6.dim("Tracking:")} ${pc6.yellow("mocked (console)")}`);
|
|
990
1022
|
console.log();
|
|
991
|
-
console.log(` ${
|
|
1023
|
+
console.log(` ${pc6.dim("Press")} ${pc6.bold("Ctrl+C")} ${pc6.dim("to stop")}`);
|
|
992
1024
|
console.log();
|
|
993
1025
|
}
|
|
994
1026
|
var init_dev = __esm({
|
|
@@ -1000,6 +1032,7 @@ var init_dev = __esm({
|
|
|
1000
1032
|
init_version();
|
|
1001
1033
|
init_pages();
|
|
1002
1034
|
init_plugin();
|
|
1035
|
+
init_projects();
|
|
1003
1036
|
}
|
|
1004
1037
|
});
|
|
1005
1038
|
|
|
@@ -1008,26 +1041,34 @@ var build_exports = {};
|
|
|
1008
1041
|
__export(build_exports, {
|
|
1009
1042
|
buildCommand: () => buildCommand
|
|
1010
1043
|
});
|
|
1011
|
-
import { resolve as
|
|
1012
|
-
import { readFileSync as
|
|
1013
|
-
import
|
|
1044
|
+
import { resolve as resolve4, join as join9 } from "path";
|
|
1045
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, statSync, readdirSync as readdirSync2 } from "fs";
|
|
1046
|
+
import pc7 from "picocolors";
|
|
1014
1047
|
async function buildCommand() {
|
|
1015
1048
|
const cwd = process.cwd();
|
|
1016
1049
|
requireAuth();
|
|
1017
1050
|
checkVersionCompatibility(cwd);
|
|
1018
1051
|
const s = spinner("Analyzing pages...");
|
|
1019
1052
|
const config = await loadConfig(cwd);
|
|
1053
|
+
if (!config.projectId) {
|
|
1054
|
+
s.stop();
|
|
1055
|
+
throw new CLIError(
|
|
1056
|
+
"MISSING_PROJECT_ID",
|
|
1057
|
+
"Missing projectId in appfunnel.config.ts.",
|
|
1058
|
+
"Run 'appfunnel dev' first to select a project, or add projectId manually."
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1020
1061
|
const pageKeys = scanPages(cwd);
|
|
1021
1062
|
const pages = await extractPageDefinitions(cwd, pageKeys);
|
|
1022
1063
|
s.stop();
|
|
1023
1064
|
validateRoutes(config, pages, pageKeys);
|
|
1024
1065
|
info(`Building ${pageKeys.length} pages...`);
|
|
1025
|
-
const outDir =
|
|
1066
|
+
const outDir = resolve4(cwd, ".appfunnel");
|
|
1026
1067
|
const { build } = await import("vite");
|
|
1027
1068
|
const react = await import("@vitejs/plugin-react");
|
|
1028
|
-
const htmlPath =
|
|
1069
|
+
const htmlPath = resolve4(cwd, "index.html");
|
|
1029
1070
|
const htmlContent = generateHtml(config.name || "AppFunnel");
|
|
1030
|
-
|
|
1071
|
+
writeFileSync4(htmlPath, htmlContent);
|
|
1031
1072
|
try {
|
|
1032
1073
|
await build({
|
|
1033
1074
|
root: cwd,
|
|
@@ -1042,7 +1083,7 @@ async function buildCommand() {
|
|
|
1042
1083
|
if (id.includes("node_modules/react")) {
|
|
1043
1084
|
return "vendor-react";
|
|
1044
1085
|
}
|
|
1045
|
-
if (id.includes("@appfunnel/sdk")) {
|
|
1086
|
+
if (id.includes("@appfunnel-dev/sdk")) {
|
|
1046
1087
|
return "vendor-sdk";
|
|
1047
1088
|
}
|
|
1048
1089
|
}
|
|
@@ -1091,24 +1132,25 @@ async function buildCommand() {
|
|
|
1091
1132
|
funnelId: config.funnelId,
|
|
1092
1133
|
pages: { ...config.pages, ...mergedPages },
|
|
1093
1134
|
routes: { ...config.routes, ...mergedRoutes },
|
|
1094
|
-
|
|
1095
|
-
queryParams: config.queryParams
|
|
1135
|
+
responses: config.responses || {},
|
|
1136
|
+
queryParams: { ...BUILTIN_QUERY_PARAMS, ...config.queryParams },
|
|
1137
|
+
data: config.data || {},
|
|
1096
1138
|
defaultLocale: config.defaultLocale,
|
|
1097
1139
|
assets,
|
|
1098
1140
|
totalSize
|
|
1099
1141
|
};
|
|
1100
|
-
|
|
1142
|
+
writeFileSync4(join9(outDir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
1101
1143
|
console.log();
|
|
1102
1144
|
success("Build complete");
|
|
1103
1145
|
console.log();
|
|
1104
|
-
console.log(` ${
|
|
1105
|
-
console.log(` ${
|
|
1106
|
-
console.log(` ${
|
|
1146
|
+
console.log(` ${pc7.dim("Output:")} .appfunnel/`);
|
|
1147
|
+
console.log(` ${pc7.dim("Pages:")} ${pageKeys.length}`);
|
|
1148
|
+
console.log(` ${pc7.dim("Size:")} ${formatSize(totalSize)}`);
|
|
1107
1149
|
console.log();
|
|
1108
1150
|
for (const asset of assets.filter((a) => a.path.endsWith(".js"))) {
|
|
1109
1151
|
const sizeStr = formatSize(asset.size);
|
|
1110
1152
|
const isOver = asset.size > MAX_PAGE_SIZE;
|
|
1111
|
-
console.log(` ${isOver ?
|
|
1153
|
+
console.log(` ${isOver ? pc7.yellow("!") : pc7.dim("\xB7")} ${pc7.dim(asset.path)} ${isOver ? pc7.yellow(sizeStr) : pc7.dim(sizeStr)}`);
|
|
1112
1154
|
}
|
|
1113
1155
|
console.log();
|
|
1114
1156
|
if (totalSize > MAX_TOTAL_SIZE) {
|
|
@@ -1131,7 +1173,22 @@ async function buildCommand() {
|
|
|
1131
1173
|
}
|
|
1132
1174
|
function validateRoutes(config, pages, pageKeys) {
|
|
1133
1175
|
const allPageKeys = new Set(pageKeys);
|
|
1134
|
-
const allVariables = new Set(
|
|
1176
|
+
const allVariables = /* @__PURE__ */ new Set();
|
|
1177
|
+
if (config.responses) {
|
|
1178
|
+
for (const key of Object.keys(config.responses)) {
|
|
1179
|
+
allVariables.add(`answers.${key}`);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
if (config.queryParams) {
|
|
1183
|
+
for (const key of Object.keys(config.queryParams)) {
|
|
1184
|
+
allVariables.add(`query.${key}`);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
if (config.data) {
|
|
1188
|
+
for (const key of Object.keys(config.data)) {
|
|
1189
|
+
allVariables.add(`data.${key}`);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1135
1192
|
for (const [pageKey, def] of Object.entries(pages)) {
|
|
1136
1193
|
if (!def.routes) continue;
|
|
1137
1194
|
for (const route of def.routes) {
|
|
@@ -1153,12 +1210,23 @@ function validateConditionVariables(condition, pageKey, allVariables) {
|
|
|
1153
1210
|
const cond = condition;
|
|
1154
1211
|
if (cond.variable && typeof cond.variable === "string") {
|
|
1155
1212
|
const prefix = cond.variable.split(".")[0];
|
|
1156
|
-
const systemPrefixes = ["page", "device", "browser", "os", "session", "system", "metadata", "user", "
|
|
1213
|
+
const systemPrefixes = ["page", "device", "browser", "os", "session", "system", "metadata", "user", "products", "card", "payment", "stripe", "subscription"];
|
|
1157
1214
|
if (!systemPrefixes.includes(prefix) && !allVariables.has(cond.variable)) {
|
|
1215
|
+
const varName = cond.variable.includes(".") ? cond.variable.split(".").slice(1).join(".") : cond.variable;
|
|
1216
|
+
let hint;
|
|
1217
|
+
if (prefix === "answers") {
|
|
1218
|
+
hint = `Add it to responses in appfunnel.config.ts: responses: { '${varName}': { type: 'string' } }`;
|
|
1219
|
+
} else if (prefix === "query") {
|
|
1220
|
+
hint = `Add it to queryParams in appfunnel.config.ts: queryParams: { '${varName}': { type: 'string' } }`;
|
|
1221
|
+
} else if (prefix === "data") {
|
|
1222
|
+
hint = `Add it to data in appfunnel.config.ts: data: { '${varName}': { type: 'string' } }`;
|
|
1223
|
+
} else {
|
|
1224
|
+
hint = `Add it to the appropriate section (responses, queryParams, or data) in appfunnel.config.ts.`;
|
|
1225
|
+
}
|
|
1158
1226
|
throw new CLIError(
|
|
1159
1227
|
"UNDEFINED_VARIABLE",
|
|
1160
1228
|
`Route condition in "${pageKey}" references variable "${cond.variable}" which is not defined.`,
|
|
1161
|
-
|
|
1229
|
+
hint
|
|
1162
1230
|
);
|
|
1163
1231
|
}
|
|
1164
1232
|
}
|
|
@@ -1173,7 +1241,7 @@ function collectAssets(outDir) {
|
|
|
1173
1241
|
function walk(dir, prefix = "") {
|
|
1174
1242
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
1175
1243
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1176
|
-
const fullPath =
|
|
1244
|
+
const fullPath = join9(dir, entry.name);
|
|
1177
1245
|
if (entry.isDirectory()) {
|
|
1178
1246
|
walk(fullPath, relPath);
|
|
1179
1247
|
} else if (entry.name !== "manifest.json" && !entry.name.startsWith(".")) {
|
|
@@ -1191,13 +1259,13 @@ function formatSize(bytes) {
|
|
|
1191
1259
|
}
|
|
1192
1260
|
function getSdkVersion2(cwd) {
|
|
1193
1261
|
try {
|
|
1194
|
-
const pkg = JSON.parse(
|
|
1262
|
+
const pkg = JSON.parse(readFileSync7(join9(cwd, "node_modules", "@appfunnel", "sdk", "package.json"), "utf-8"));
|
|
1195
1263
|
return pkg.version;
|
|
1196
1264
|
} catch {
|
|
1197
1265
|
return "0.0.0";
|
|
1198
1266
|
}
|
|
1199
1267
|
}
|
|
1200
|
-
var MAX_TOTAL_SIZE, MAX_PAGE_SIZE;
|
|
1268
|
+
var MAX_TOTAL_SIZE, MAX_PAGE_SIZE, BUILTIN_QUERY_PARAMS;
|
|
1201
1269
|
var init_build = __esm({
|
|
1202
1270
|
"src/commands/build.ts"() {
|
|
1203
1271
|
"use strict";
|
|
@@ -1212,6 +1280,13 @@ var init_build = __esm({
|
|
|
1212
1280
|
init_errors();
|
|
1213
1281
|
MAX_TOTAL_SIZE = 2 * 1024 * 1024;
|
|
1214
1282
|
MAX_PAGE_SIZE = 500 * 1024;
|
|
1283
|
+
BUILTIN_QUERY_PARAMS = {
|
|
1284
|
+
utm_source: { type: "string" },
|
|
1285
|
+
utm_medium: { type: "string" },
|
|
1286
|
+
utm_campaign: { type: "string" },
|
|
1287
|
+
utm_content: { type: "string" },
|
|
1288
|
+
utm_term: { type: "string" }
|
|
1289
|
+
};
|
|
1215
1290
|
}
|
|
1216
1291
|
});
|
|
1217
1292
|
|
|
@@ -1300,9 +1375,9 @@ var publish_exports = {};
|
|
|
1300
1375
|
__export(publish_exports, {
|
|
1301
1376
|
publishCommand: () => publishCommand
|
|
1302
1377
|
});
|
|
1303
|
-
import { resolve as
|
|
1304
|
-
import { readFileSync as
|
|
1305
|
-
import
|
|
1378
|
+
import { resolve as resolve5, join as join10 } from "path";
|
|
1379
|
+
import { readFileSync as readFileSync8, existsSync as existsSync5 } from "fs";
|
|
1380
|
+
import pc8 from "picocolors";
|
|
1306
1381
|
function getMimeType(path) {
|
|
1307
1382
|
const ext = path.substring(path.lastIndexOf("."));
|
|
1308
1383
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -1312,8 +1387,8 @@ async function publishCommand() {
|
|
|
1312
1387
|
const creds = requireAuth();
|
|
1313
1388
|
checkVersionCompatibility(cwd);
|
|
1314
1389
|
const config = await loadConfig(cwd);
|
|
1315
|
-
const outDir =
|
|
1316
|
-
const manifestPath =
|
|
1390
|
+
const outDir = resolve5(cwd, ".appfunnel");
|
|
1391
|
+
const manifestPath = join10(outDir, "manifest.json");
|
|
1317
1392
|
if (!existsSync5(manifestPath)) {
|
|
1318
1393
|
throw new CLIError(
|
|
1319
1394
|
"BUILD_NOT_FOUND",
|
|
@@ -1321,12 +1396,12 @@ async function publishCommand() {
|
|
|
1321
1396
|
"Run 'appfunnel build' first."
|
|
1322
1397
|
);
|
|
1323
1398
|
}
|
|
1324
|
-
const manifest = JSON.parse(
|
|
1399
|
+
const manifest = JSON.parse(readFileSync8(manifestPath, "utf-8"));
|
|
1325
1400
|
const assets = manifest.assets || [];
|
|
1326
1401
|
const s = spinner("Uploading build...");
|
|
1327
1402
|
const assetPayloads = [];
|
|
1328
1403
|
for (const asset of assets) {
|
|
1329
|
-
const fullPath =
|
|
1404
|
+
const fullPath = join10(outDir, asset.path);
|
|
1330
1405
|
if (!existsSync5(fullPath)) {
|
|
1331
1406
|
s.stop();
|
|
1332
1407
|
throw new CLIError(
|
|
@@ -1337,7 +1412,7 @@ async function publishCommand() {
|
|
|
1337
1412
|
}
|
|
1338
1413
|
assetPayloads.push({
|
|
1339
1414
|
path: asset.path,
|
|
1340
|
-
content:
|
|
1415
|
+
content: readFileSync8(fullPath),
|
|
1341
1416
|
contentType: getMimeType(asset.path)
|
|
1342
1417
|
});
|
|
1343
1418
|
}
|
|
@@ -1370,9 +1445,9 @@ async function publishCommand() {
|
|
|
1370
1445
|
console.log();
|
|
1371
1446
|
success("Published successfully");
|
|
1372
1447
|
console.log();
|
|
1373
|
-
console.log(` ${
|
|
1374
|
-
console.log(` ${
|
|
1375
|
-
console.log(` ${
|
|
1448
|
+
console.log(` ${pc8.dim("Build ID:")} ${result.buildId}`);
|
|
1449
|
+
console.log(` ${pc8.dim("URL:")} ${pc8.cyan(result.url)}`);
|
|
1450
|
+
console.log(` ${pc8.dim("Assets:")} ${assets.length} files`);
|
|
1376
1451
|
console.log();
|
|
1377
1452
|
}
|
|
1378
1453
|
var MIME_TYPES;
|
|
@@ -1401,13 +1476,13 @@ var init_publish = __esm({
|
|
|
1401
1476
|
|
|
1402
1477
|
// src/index.ts
|
|
1403
1478
|
init_errors();
|
|
1404
|
-
import { readFileSync as
|
|
1479
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
1405
1480
|
import { Command } from "commander";
|
|
1406
|
-
import
|
|
1481
|
+
import pc9 from "picocolors";
|
|
1407
1482
|
function getCliVersion2() {
|
|
1408
1483
|
try {
|
|
1409
1484
|
const pkg = JSON.parse(
|
|
1410
|
-
|
|
1485
|
+
readFileSync9(new URL("../package.json", import.meta.url), "utf-8")
|
|
1411
1486
|
);
|
|
1412
1487
|
return pkg.version;
|
|
1413
1488
|
} catch {
|
|
@@ -1450,9 +1525,9 @@ async function main() {
|
|
|
1450
1525
|
console.error(formatError(err));
|
|
1451
1526
|
process.exit(1);
|
|
1452
1527
|
}
|
|
1453
|
-
console.error(`${
|
|
1528
|
+
console.error(`${pc9.red("ERROR")}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1454
1529
|
if (err instanceof Error && err.stack) {
|
|
1455
|
-
console.error(
|
|
1530
|
+
console.error(pc9.dim(err.stack));
|
|
1456
1531
|
}
|
|
1457
1532
|
process.exit(1);
|
|
1458
1533
|
}
|
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/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/sdk'\n\nexport default defineConfig({\n projectId: '${projectId}',\n name: '${name}',\n defaultLocale: 'en',\n\n variables: {\n 'answers.goal': { type: 'string' },\n },\n\n queryParams: ['utm_source', 'utm_medium', 'utm_campaign'],\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, useVariable, useNavigation } from '@appfunnel/sdk'\n\nexport const page = definePage({\n name: 'Landing',\n type: 'default',\n routes: [],\n})\n\nexport default function Landing() {\n const [goal, setGoal] = useVariable<string>('answers.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 AppFunnelConfig {\n projectId: string\n name: string\n funnelId?: string\n initialPage?: string\n defaultLocale?: string\n variables: Record<string, { type: string; default?: unknown; persist?: boolean }>\n queryParams?: string[]\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\\/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/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/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,\n \"Run 'npm install @appfunnel/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/sdk is not installed.',\n \"Run 'npm install @appfunnel/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/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 } 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/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 variables: config.variables,\n queryParams: config.queryParams || [],\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: { variables: Record<string, unknown>; routes?: Record<string, unknown[]> },\n pages: Record<string, { routes?: Array<{ to: string; when?: unknown }> }>,\n pageKeys: string[],\n): void {\n const allPageKeys = new Set(pageKeys)\n const allVariables = new Set(Object.keys(config.variables))\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.* / query.*\n const prefix = cond.variable.split('.')[0]\n const systemPrefixes = ['page', 'device', 'browser', 'os', 'session', 'system', 'metadata', 'user', 'query', 'products', 'card', 'payment', 'stripe', 'subscription']\n if (!systemPrefixes.includes(prefix) && !allVariables.has(cond.variable)) {\n throw new CLIError(\n 'UNDEFINED_VARIABLE',\n `Route condition in \"${pageKey}\" references variable \"${cond.variable}\" which is not defined.`,\n `Add it to variables in appfunnel.config.ts: '${cond.variable}': { type: 'string' }`,\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 version: string\n}\n\n/**\n * Check that CLI major.minor matches the installed @appfunnel-dev/sdk version.\n */\nexport function checkVersionCompatibility(cwd: string): void {\n const cliVersion = getCliVersion()\n const sdkVersion = getSdkVersion(cwd)\n\n const [cliMajor, cliMinor] = cliVersion.split('.').map(Number)\n const [sdkMajor, sdkMinor] = sdkVersion.split('.').map(Number)\n\n if (cliMajor !== sdkMajor || cliMinor !== sdkMinor) {\n throw new CLIError(\n 'VERSION_MISMATCH',\n `CLI version ${cliVersion} requires @appfunnel-dev/sdk ^${cliMajor}.${cliMinor}.0, but found ${sdkVersion}.`,\n \"Run 'npm install @appfunnel-dev/sdk@latest' to update.\",\n )\n }\n}\n\nfunction getCliVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'),\n ) as PackageJson\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n\nfunction getSdkVersion(cwd: string): string {\n try {\n const pkgPath = join(cwd, 'node_modules', '@appfunnel', 'sdk', 'package.json')\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as PackageJson\n return pkg.version\n } catch {\n throw new CLIError(\n 'VERSION_MISMATCH',\n '@appfunnel-dev/sdk is not installed.',\n \"Run 'npm install @appfunnel-dev/sdk' to install it.\",\n )\n }\n}\n","import { readdirSync, readFileSync, existsSync } from 'node:fs'\nimport { join, basename } from 'node:path'\nimport { resolvePagesDir } from '../lib/config.js'\nimport { CLIError } from '../lib/errors.js'\nimport type ts from 'typescript'\n\nexport interface PageDefinition {\n name: string\n type?: string\n slug?: string\n routes?: Array<{ to: string; when?: unknown }>\n}\n\n/**\n * Scan src/pages/ for .tsx files and return page keys.\n */\nexport function scanPages(cwd: string): string[] {\n const pagesDir = resolvePagesDir(cwd)\n\n if (!existsSync(pagesDir)) {\n throw new CLIError(\n 'NO_PAGES',\n 'No src/pages/ directory found.',\n 'Create src/pages/ and add at least one .tsx page file.',\n )\n }\n\n const files = readdirSync(pagesDir)\n .filter((f) => f.endsWith('.tsx') && !f.startsWith('_'))\n .map((f) => basename(f, '.tsx'))\n .sort()\n\n if (files.length === 0) {\n throw new CLIError(\n 'NO_PAGES',\n 'No page files found in src/pages/.',\n 'Add .tsx files to src/pages/. Each file is a funnel page.',\n )\n }\n\n return files\n}\n\n/**\n * Extract definePage() metadata from each page file using the TypeScript compiler API.\n */\nexport async function extractPageDefinitions(\n cwd: string,\n pageKeys: string[],\n): Promise<Record<string, PageDefinition>> {\n const ts = await import('typescript') as typeof import('typescript')\n const pagesDir = resolvePagesDir(cwd)\n const result: Record<string, PageDefinition> = {}\n\n for (const key of pageKeys) {\n const filePath = join(pagesDir, `${key}.tsx`)\n const source = readFileSync(filePath, 'utf-8')\n\n const definition = extractDefinePage(ts, source, filePath)\n if (definition) {\n result[key] = definition\n } else {\n // Page without definePage() — use defaults\n result[key] = {\n name: key,\n type: 'default',\n }\n }\n }\n\n return result\n}\n\n/**\n * Parse a single page file and extract the definePage() argument.\n */\nfunction extractDefinePage(\n ts: typeof import('typescript'),\n source: string,\n fileName: string,\n): PageDefinition | null {\n const sourceFile = ts.createSourceFile(\n fileName,\n source,\n ts.ScriptTarget.Latest,\n true,\n ts.ScriptKind.TSX,\n )\n\n let definition: PageDefinition | null = null\n\n function visit(node: ts.Node): void {\n // Look for: export const page = definePage({ ... })\n if (ts.isVariableStatement(node)) {\n const isExported = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.ExportKeyword,\n )\n if (!isExported) return\n\n for (const decl of node.declarationList.declarations) {\n if (\n ts.isIdentifier(decl.name) &&\n decl.name.text === 'page' &&\n decl.initializer &&\n ts.isCallExpression(decl.initializer)\n ) {\n const call = decl.initializer\n const callee = call.expression\n\n // Check if callee is \"definePage\"\n if (ts.isIdentifier(callee) && callee.text === 'definePage') {\n const arg = call.arguments[0]\n if (arg && ts.isObjectLiteralExpression(arg)) {\n definition = extractObjectLiteral(ts, arg) as unknown as PageDefinition\n }\n }\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n ts.forEachChild(sourceFile, visit)\n return definition\n}\n\n/**\n * Recursively extract a TypeScript object literal into a plain JS object.\n */\nfunction extractObjectLiteral(\n ts: typeof import('typescript'),\n node: ts.ObjectLiteralExpression,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const prop of node.properties) {\n if (!ts.isPropertyAssignment(prop)) continue\n if (!ts.isIdentifier(prop.name) && !ts.isStringLiteral(prop.name)) continue\n\n const key = ts.isIdentifier(prop.name) ? prop.name.text : prop.name.text\n result[key] = extractValue(ts, prop.initializer)\n }\n\n return result\n}\n\n/**\n * Extract a static value from a TypeScript AST node.\n */\nfunction extractValue(\n ts: typeof import('typescript'),\n node: ts.Expression,\n): unknown {\n // String literal\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text\n }\n\n // Numeric literal\n if (ts.isNumericLiteral(node)) {\n return Number(node.text)\n }\n\n // Boolean / null / undefined\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false\n if (node.kind === ts.SyntaxKind.NullKeyword) return null\n if (node.kind === ts.SyntaxKind.UndefinedKeyword) return undefined\n\n // Array literal\n if (ts.isArrayLiteralExpression(node)) {\n return node.elements.map((el) => extractValue(ts, el))\n }\n\n // Object literal\n if (ts.isObjectLiteralExpression(node)) {\n return extractObjectLiteral(ts, node)\n }\n\n // Prefix unary (negative numbers)\n if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken) {\n const operand = extractValue(ts, node.operand)\n if (typeof operand === 'number') return -operand\n }\n\n // Can't statically evaluate — return undefined\n return undefined\n}\n","import { join } from 'node:path'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\n\ninterface EntryOptions {\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n pagesDir: string\n funnelTsxPath: string\n isDev: boolean\n}\n\n/**\n * Generate the virtual entry module source code.\n *\n * This creates a mini SPA that:\n * - Mounts FunnelProvider once\n * - Wraps with the user's funnel.tsx\n * - Client-side routes between pages via pushState\n * - Lazy-loads page components\n */\nexport function generateEntrySource(options: EntryOptions): string {\n const { config, pages, pagesDir, funnelTsxPath, isDev } = options\n const pageKeys = Object.keys(pages)\n\n // Merge definePage() metadata into config\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Override config pages/routes with extracted ones\n const fullConfig = {\n ...config,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n }\n\n // Generate lazy imports for each page\n const pageImports = pageKeys\n .map(\n (key) =>\n ` '${key}': lazy(() => import('${join(pagesDir, key + '.tsx').replace(/\\\\/g, '/')}')),`,\n )\n .join('\\n')\n\n // Build slug → key mapping\n const slugMap: Record<string, string> = {}\n for (const [key, def] of Object.entries(pages)) {\n slugMap[def.slug || key] = key\n }\n\n const trackingCode = isDev\n ? `\n// Dev mode: mock tracking — log events to console\nconst originalFetch = globalThis.fetch;\nglobalThis.__APPFUNNEL_DEV__ = true;\n`\n : ''\n\n return `\nimport { StrictMode, lazy, Suspense, useState, useEffect, useCallback } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { FunnelProvider } from '@appfunnel-dev/sdk/internal'\nimport FunnelWrapper from '${funnelTsxPath.replace(/\\\\/g, '/')}'\n\n${trackingCode}\n\nconst pages = {\n${pageImports}\n}\n\nconst config = ${JSON.stringify(fullConfig, null, 2)}\n\nconst slugToKey = ${JSON.stringify(slugMap)}\nconst keyToSlug = ${JSON.stringify(\n Object.fromEntries(Object.entries(slugMap).map(([s, k]) => [k, s])),\n )}\n\nfunction getInitialPage() {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n return slugToKey[path] || '${config.initialPage || pageKeys[0] || 'index'}'\n}\n\nfunction App() {\n const [currentPage, setCurrentPage] = useState(getInitialPage)\n\n useEffect(() => {\n const handlePopState = () => {\n const path = window.location.pathname.split('/').filter(Boolean).pop() || ''\n const pageKey = slugToKey[path]\n if (pageKey && pageKey !== currentPage) {\n setCurrentPage(pageKey)\n }\n }\n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [currentPage])\n\n // Expose navigation to FunnelProvider's router\n useEffect(() => {\n window.__APPFUNNEL_NAVIGATE__ = (pageKey) => {\n setCurrentPage(pageKey)\n const slug = keyToSlug[pageKey] || pageKey\n window.history.pushState(null, '', '/' + slug)\n }\n return () => { delete window.__APPFUNNEL_NAVIGATE__ }\n }, [])\n\n const PageComponent = pages[currentPage]\n\n if (!PageComponent) {\n return <div style={{ padding: '2rem', color: 'red' }}>Page not found: {currentPage}</div>\n }\n\n return (\n <FunnelProvider\n config={config}\n initialPage={currentPage}\n apiBaseUrl={${isDev ? \"''\" : \"config.settings?.apiBaseUrl || ''\"}}\n >\n <FunnelWrapper>\n <Suspense fallback={null}>\n <PageComponent />\n </Suspense>\n </FunnelWrapper>\n </FunnelProvider>\n )\n}\n\ncreateRoot(document.getElementById('root')).render(\n <StrictMode>\n <App />\n </StrictMode>\n)\n`\n}\n","/**\n * Generate the index.html template for the dev server and production build.\n */\nexport function generateHtml(title: string = 'AppFunnel'): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${title}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/@appfunnel/entry\"></script>\n </body>\n</html>`\n}\n","import { resolve, join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { AppFunnelConfig } from '../lib/config.js'\nimport type { PageDefinition } from '../extract/pages.js'\nimport { generateEntrySource } from './entry.js'\nimport { generateHtml } from './html.js'\n\nconst VIRTUAL_ENTRY_ID = '@appfunnel/entry'\nconst RESOLVED_VIRTUAL_ENTRY_ID = '\\0' + VIRTUAL_ENTRY_ID\nconst VIRTUAL_HTML_ID = '@appfunnel/index.html'\n\ninterface PluginOptions {\n cwd: string\n config: AppFunnelConfig\n pages: Record<string, PageDefinition>\n isDev: boolean\n onPagesChange?: () => Promise<void>\n}\n\nexport function appfunnelPlugin(options: PluginOptions): Plugin {\n const { cwd, config, isDev } = options\n let pages = options.pages\n const pagesDir = resolve(cwd, 'src', 'pages')\n const funnelTsxPath = resolve(cwd, 'src', 'funnel.tsx')\n\n let server: ViteDevServer | undefined\n\n function getEntrySource(): string {\n return generateEntrySource({\n config,\n pages,\n pagesDir,\n funnelTsxPath,\n isDev,\n })\n }\n\n return {\n name: 'appfunnel',\n\n config() {\n return {\n resolve: {\n alias: {\n '@': resolve(cwd, 'src'),\n },\n },\n // Ensure we can import .tsx files\n esbuild: {\n jsx: 'automatic',\n },\n optimizeDeps: {\n include: ['react', 'react-dom', 'react/jsx-runtime'],\n },\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n return null\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n return getEntrySource()\n }\n return null\n },\n\n configureServer(devServer) {\n server = devServer\n\n // Watch for page file additions/removals\n const watcher = devServer.watcher\n watcher.add(pagesDir)\n\n const handlePagesChange = async () => {\n if (options.onPagesChange) {\n await options.onPagesChange()\n }\n // Invalidate the virtual module and trigger full reload\n const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ENTRY_ID)\n if (mod) {\n devServer.moduleGraph.invalidateModule(mod)\n }\n devServer.ws.send({ type: 'full-reload' })\n }\n\n watcher.on('add', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n watcher.on('unlink', (file) => {\n if (file.startsWith(pagesDir) && file.endsWith('.tsx')) {\n handlePagesChange()\n }\n })\n\n // Watch appfunnel.config.ts for changes → full reload\n const configPath = join(cwd, 'appfunnel.config.ts')\n if (existsSync(configPath)) {\n watcher.add(configPath)\n watcher.on('change', (file) => {\n if (file === configPath) {\n devServer.ws.send({ type: 'full-reload' })\n }\n })\n }\n\n // SPA fallback middleware — serve index.html for all routes\n return () => {\n devServer.middlewares.use((req, res, next) => {\n // Skip Vite internal routes and static assets\n if (\n req.url?.startsWith('/@') ||\n req.url?.startsWith('/node_modules') ||\n req.url?.startsWith('/src') ||\n req.url?.includes('.')\n ) {\n return next()\n }\n\n // Serve the HTML shell for all other routes\n const html = generateHtml(config.name || 'AppFunnel')\n devServer.transformIndexHtml(req.url || '/', html).then((transformed) => {\n res.statusCode = 200\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n }).catch(next)\n })\n }\n },\n\n // For production build: inject the HTML as the input\n transformIndexHtml(html) {\n return html\n },\n }\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { resolve, join } from 'node:path'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, resolvePagesDir } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { promptForProject } from '../lib/projects.js'\n\nexport async function devCommand(options: { port?: number }): Promise<void> {\n const cwd = process.cwd()\n const port = options.port || 5173\n\n // 1. Auth check\n const creds = requireAuth()\n\n // 2. Version check\n checkVersionCompatibility(cwd)\n\n // 3. Load config\n const s = log.spinner('Loading config...')\n const config = await loadConfig(cwd)\n s.stop()\n\n // 4. If no projectId, prompt for one and update the config file\n if (!config.projectId) {\n log.info('No projectId found in appfunnel.config.ts')\n const projectId = await promptForProject(creds.token)\n config.projectId = projectId\n\n // Write projectId back to the config file\n const configPath = join(cwd, 'appfunnel.config.ts')\n const configSource = readFileSync(configPath, 'utf-8')\n const updated = configSource.replace(\n /projectId:\\s*['\"].*?['\"]/,\n `projectId: '${projectId}'`,\n )\n if (updated !== configSource) {\n writeFileSync(configPath, updated)\n log.success(`Updated projectId in appfunnel.config.ts`)\n } else {\n // If regex didn't match (e.g. projectId field doesn't exist), warn\n log.warn(`Could not auto-update appfunnel.config.ts — add projectId: '${projectId}' manually.`)\n }\n }\n\n // 5. Scan and extract pages\n const s2 = log.spinner('Scanning pages...')\n let pageKeys = scanPages(cwd)\n let pages = await extractPageDefinitions(cwd, pageKeys)\n s2.stop()\n\n log.info(`Found ${pageKeys.length} pages: ${pageKeys.join(', ')}`)\n\n // 6. Start Vite dev server\n const { createServer } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n const server = await createServer({\n root: cwd,\n server: {\n port,\n strictPort: false,\n },\n plugins: [\n react.default(),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: true,\n async onPagesChange() {\n // Re-scan pages when files are added/removed\n pageKeys = scanPages(cwd)\n pages = await extractPageDefinitions(cwd, pageKeys)\n log.info(`Pages updated: ${pageKeys.join(', ')}`)\n },\n }),\n ],\n css: {\n postcss: cwd,\n },\n })\n\n await server.listen()\n\n const address = server.resolvedUrls?.local?.[0] || `http://localhost:${port}`\n\n console.log()\n console.log(` ${pc.bold(config.name || 'AppFunnel')} dev server`)\n console.log()\n console.log(` ${pc.dim('Local:')} ${pc.cyan(address)}`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Tracking:')} ${pc.yellow('mocked (console)')}`)\n console.log()\n console.log(` ${pc.dim('Press')} ${pc.bold('Ctrl+C')} ${pc.dim('to stop')}`)\n console.log()\n}\n","import { resolve, join } from 'node:path'\nimport { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig, type AppFunnelConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { scanPages, extractPageDefinitions } from '../extract/pages.js'\nimport { appfunnelPlugin } from '../vite/plugin.js'\nimport { generateHtml } from '../vite/html.js'\nimport { formatWarning } from '../lib/errors.js'\nimport { CLIError } from '../lib/errors.js'\n\nconst MAX_TOTAL_SIZE = 2 * 1024 * 1024 // 2MB\nconst MAX_PAGE_SIZE = 500 * 1024 // 500KB\n\n/** UTM query params — always included, no config needed */\nconst BUILTIN_QUERY_PARAMS: Record<string, { type: string }> = {\n utm_source: { type: 'string' },\n utm_medium: { type: 'string' },\n utm_campaign: { type: 'string' },\n utm_content: { type: 'string' },\n utm_term: { type: 'string' },\n}\n\nexport async function buildCommand(): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config + pages\n const s = log.spinner('Analyzing pages...')\n const config = await loadConfig(cwd)\n\n if (!config.projectId) {\n s.stop()\n throw new CLIError(\n 'MISSING_PROJECT_ID',\n 'Missing projectId in appfunnel.config.ts.',\n \"Run 'appfunnel dev' first to select a project, or add projectId manually.\",\n )\n }\n\n const pageKeys = scanPages(cwd)\n const pages = await extractPageDefinitions(cwd, pageKeys)\n s.stop()\n\n // 3. Validate routes\n validateRoutes(config, pages, pageKeys)\n\n log.info(`Building ${pageKeys.length} pages...`)\n\n // 4. Build with Vite\n const outDir = resolve(cwd, '.appfunnel')\n const { build } = await import('vite')\n const react = await import('@vitejs/plugin-react')\n\n // Write index.html for Vite to use as entry\n const htmlPath = resolve(cwd, 'index.html')\n const htmlContent = generateHtml(config.name || 'AppFunnel')\n writeFileSync(htmlPath, htmlContent)\n\n try {\n await build({\n root: cwd,\n build: {\n outDir,\n emptyOutDir: true,\n sourcemap: false,\n minify: 'esbuild',\n rollupOptions: {\n output: {\n manualChunks(id) {\n if (id.includes('node_modules/react')) {\n return 'vendor-react'\n }\n if (id.includes('@appfunnel-dev/sdk')) {\n return 'vendor-sdk'\n }\n },\n },\n },\n },\n plugins: [\n react.default(),\n appfunnelPlugin({\n cwd,\n config,\n pages,\n isDev: false,\n }),\n ],\n css: {\n postcss: cwd,\n },\n logLevel: 'warn',\n })\n } finally {\n // Clean up the temporary index.html\n try {\n const { unlinkSync } = await import('node:fs')\n unlinkSync(htmlPath)\n } catch { /* ignore */ }\n }\n\n // 5. Generate manifest\n const mergedPages: Record<string, unknown> = {}\n const mergedRoutes: Record<string, unknown> = {}\n\n for (const [key, def] of Object.entries(pages)) {\n mergedPages[key] = {\n name: def.name || key,\n type: def.type || 'default',\n slug: def.slug || key,\n }\n if (def.routes) {\n mergedRoutes[key] = def.routes\n }\n }\n\n // Collect asset info\n const assets = collectAssets(outDir)\n const totalSize = assets.reduce((sum, a) => sum + a.size, 0)\n\n const manifest = {\n version: 1,\n sdkVersion: getSdkVersion(cwd),\n projectId: config.projectId,\n funnelId: config.funnelId,\n pages: { ...config.pages, ...mergedPages },\n routes: { ...config.routes, ...mergedRoutes },\n responses: config.responses || {},\n queryParams: { ...BUILTIN_QUERY_PARAMS, ...config.queryParams },\n data: config.data || {},\n defaultLocale: config.defaultLocale,\n assets,\n totalSize,\n }\n\n writeFileSync(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n')\n\n // 6. Print report\n console.log()\n log.success('Build complete')\n console.log()\n console.log(` ${pc.dim('Output:')} .appfunnel/`)\n console.log(` ${pc.dim('Pages:')} ${pageKeys.length}`)\n console.log(` ${pc.dim('Size:')} ${formatSize(totalSize)}`)\n console.log()\n\n // Print per-asset sizes\n for (const asset of assets.filter(a => a.path.endsWith('.js'))) {\n const sizeStr = formatSize(asset.size)\n const isOver = asset.size > MAX_PAGE_SIZE\n console.log(` ${isOver ? pc.yellow('!') : pc.dim('·')} ${pc.dim(asset.path)} ${isOver ? pc.yellow(sizeStr) : pc.dim(sizeStr)}`)\n }\n console.log()\n\n // Warn on size limits\n if (totalSize > MAX_TOTAL_SIZE) {\n console.log(formatWarning(\n 'BUNDLE_TOO_LARGE',\n `Total bundle size (${formatSize(totalSize)}) exceeds the 2MB limit.`,\n 'This will be rejected on publish. Reduce dependencies or code-split.',\n ))\n console.log()\n }\n\n for (const asset of assets) {\n if (asset.size > MAX_PAGE_SIZE && asset.path.endsWith('.js')) {\n console.log(formatWarning(\n 'PAGE_SIZE',\n `${asset.path} is ${formatSize(asset.size)} (limit: 500KB).`,\n 'Consider reducing dependencies in this page.',\n ))\n }\n }\n}\n\nfunction validateRoutes(\n config: AppFunnelConfig,\n pages: Record<string, { routes?: Array<{ to: string; when?: unknown }> }>,\n pageKeys: string[],\n): void {\n const allPageKeys = new Set(pageKeys)\n\n // Build full set of known variables from all namespaced sections\n const allVariables = new Set<string>()\n if (config.responses) {\n for (const key of Object.keys(config.responses)) {\n allVariables.add(`answers.${key}`)\n }\n }\n if (config.queryParams) {\n for (const key of Object.keys(config.queryParams)) {\n allVariables.add(`query.${key}`)\n }\n }\n if (config.data) {\n for (const key of Object.keys(config.data)) {\n allVariables.add(`data.${key}`)\n }\n }\n\n // Check routes from definePage()\n for (const [pageKey, def] of Object.entries(pages)) {\n if (!def.routes) continue\n for (const route of def.routes) {\n if (!allPageKeys.has(route.to)) {\n throw new CLIError(\n 'INVALID_ROUTE',\n `Page \"${pageKey}\" routes to \"${route.to}\" which does not exist.`,\n `Available pages: ${pageKeys.join(', ')}. Check src/pages/${pageKey}.tsx.`,\n )\n }\n\n // Validate condition variable references\n if (route.when) {\n validateConditionVariables(route.when, pageKey, allVariables)\n }\n }\n }\n}\n\nfunction validateConditionVariables(\n condition: unknown,\n pageKey: string,\n allVariables: Set<string>,\n): void {\n if (!condition || typeof condition !== 'object') return\n\n const cond = condition as Record<string, unknown>\n\n // Simple condition\n if (cond.variable && typeof cond.variable === 'string') {\n // Skip system variables (page.*, device.*, etc.) and user.*\n const prefix = cond.variable.split('.')[0]\n const systemPrefixes = ['page', 'device', 'browser', 'os', 'session', 'system', 'metadata', 'user', 'products', 'card', 'payment', 'stripe', 'subscription']\n if (!systemPrefixes.includes(prefix) && !allVariables.has(cond.variable)) {\n // Suggest the right config section based on the prefix\n const varName = cond.variable.includes('.') ? cond.variable.split('.').slice(1).join('.') : cond.variable\n let hint: string\n if (prefix === 'answers') {\n hint = `Add it to responses in appfunnel.config.ts: responses: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'query') {\n hint = `Add it to queryParams in appfunnel.config.ts: queryParams: { '${varName}': { type: 'string' } }`\n } else if (prefix === 'data') {\n hint = `Add it to data in appfunnel.config.ts: data: { '${varName}': { type: 'string' } }`\n } else {\n hint = `Add it to the appropriate section (responses, queryParams, or data) in appfunnel.config.ts.`\n }\n throw new CLIError(\n 'UNDEFINED_VARIABLE',\n `Route condition in \"${pageKey}\" references variable \"${cond.variable}\" which is not defined.`,\n hint,\n )\n }\n }\n\n // Condition group\n if (Array.isArray(cond.rules)) {\n for (const rule of cond.rules) {\n validateConditionVariables(rule, pageKey, allVariables)\n }\n }\n}\n\nfunction collectAssets(outDir: string): Array<{ path: string; size: number }> {\n const assets: Array<{ path: string; size: number }> = []\n\n function walk(dir: string, prefix: string = ''): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n walk(fullPath, relPath)\n } else if (entry.name !== 'manifest.json' && !entry.name.startsWith('.')) {\n assets.push({ path: relPath, size: statSync(fullPath).size })\n }\n }\n }\n\n walk(outDir)\n return assets\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`\n return `${(bytes / (1024 * 1024)).toFixed(2)}MB`\n}\n\nfunction getSdkVersion(cwd: string): string {\n try {\n const pkg = JSON.parse(readFileSync(join(cwd, 'node_modules', '@appfunnel', 'sdk', 'package.json'), 'utf-8'))\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n","import { CLIError } from './errors.js'\n\nconst DEFAULT_API_BASE = 'https://api.appfunnel.net'\n\ninterface ApiOptions {\n\ttoken: string\n\tapiBaseUrl?: string\n}\n\nasync function apiFetch(\n\tpath: string,\n\toptions: ApiOptions & RequestInit\n): Promise<Response> {\n\tconst { token, apiBaseUrl, ...fetchOpts } = options\n\tconst base = apiBaseUrl || DEFAULT_API_BASE\n\tconst url = `${base}${path}`\n\n\t// Don't set Content-Type for FormData — let the browser set the boundary\n\tconst isFormData = fetchOpts.body instanceof FormData\n\tconst headers: Record<string, string> = {\n\t\tAuthorization: token,\n\t\t...((fetchOpts.headers as Record<string, string>) || {}),\n\t}\n\tif (!isFormData) {\n\t\theaders['Content-Type'] = 'application/json'\n\t}\n\n\tconst response = await fetch(url, {\n\t\t...fetchOpts,\n\t\theaders,\n\t})\n\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => '')\n\t\tlet message = `API request failed: ${response.status} ${response.statusText}`\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(body)\n\t\t\tif (parsed.error) message = parsed.error\n\t\t\tif (parsed.message) message = parsed.message\n\t\t} catch {\n\t\t\t/* ignore parse errors */\n\t\t}\n\t\tconst error = new CLIError('API_ERROR', message)\n\t\terror.statusCode = response.status\n\t\tthrow error\n\t}\n\n\treturn response\n}\n\n/**\n * Fetch enriched price data for all store price IDs.\n */\nexport async function fetchPrices(\n\tprojectId: string,\n\tstorePriceIds: string[],\n\toptions: ApiOptions\n): Promise<Map<string, unknown>> {\n\tif (storePriceIds.length === 0) return new Map()\n\n\tconst response = await apiFetch(`/project/${projectId}/headless/prices`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ storePriceIds }),\n\t})\n\n\tconst data = (await response.json()) as { prices: Record<string, unknown> }\n\treturn new Map(Object.entries(data.prices || {}))\n}\n\n/**\n * Create a new headless funnel under a project.\n */\nexport async function createHeadlessFunnel(\n\tprojectId: string,\n\tname: string,\n\toptions: ApiOptions\n): Promise<{ funnelId: string; identifier: string }> {\n\tconst response = await apiFetch(`/project/${projectId}/headless/funnels`, {\n\t\t...options,\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({ name }),\n\t})\n\n\treturn (await response.json()) as { funnelId: string; identifier: string }\n}\n\n/**\n * Publish a headless build.\n */\nexport async function publishBuild(\n\tprojectId: string,\n\tfunnelId: string,\n\tmanifest: unknown,\n\tassets: Array<{ path: string; content: Buffer; contentType: string }>,\n\toptions: ApiOptions\n): Promise<{ buildId: string; url: string }> {\n\t// Use multipart form data for assets\n\tconst formData = new FormData()\n\tformData.set('manifest', JSON.stringify(manifest))\n\tformData.set('funnelId', funnelId)\n\n\tfor (const asset of assets) {\n\t\tformData.append(\n\t\t\t'assets',\n\t\t\tnew Blob([new Uint8Array(asset.content)], { type: asset.contentType }),\n\t\t\tasset.path\n\t\t)\n\t}\n\n\ttry {\n\t\tconst response = await apiFetch(`/project/${projectId}/headless/publish`, {\n\t\t\t...options,\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t})\n\t\treturn (await response.json()) as { buildId: string; url: string }\n\t} catch (err) {\n\t\tif (err instanceof CLIError && err.code === 'API_ERROR') {\n\t\t\tif (err.statusCode === 413) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'BUNDLE_TOO_LARGE',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Reduce page bundle sizes. Check for large dependencies.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (err.statusCode === 409) {\n\t\t\t\tthrow new CLIError(\n\t\t\t\t\t'FUNNEL_NOT_HEADLESS',\n\t\t\t\t\terr.message,\n\t\t\t\t\t'Create a new headless funnel from the dashboard, or remove funnelId from config.'\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow new CLIError('PUBLISH_FAILED', err.message)\n\t\t}\n\t\tthrow err\n\t}\n}\n","import { resolve, join } from 'node:path'\nimport { readFileSync, existsSync } from 'node:fs'\nimport pc from 'picocolors'\nimport * as log from '../lib/logger.js'\nimport { requireAuth } from '../lib/auth.js'\nimport { loadConfig } from '../lib/config.js'\nimport { checkVersionCompatibility } from '../lib/version.js'\nimport { publishBuild } from '../lib/api.js'\nimport { CLIError } from '../lib/errors.js'\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.html': 'text/html',\n '.json': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n}\n\nfunction getMimeType(path: string): string {\n const ext = path.substring(path.lastIndexOf('.'))\n return MIME_TYPES[ext] || 'application/octet-stream'\n}\n\nexport async function publishCommand(): Promise<void> {\n const cwd = process.cwd()\n\n // 1. Auth + version check\n const creds = requireAuth()\n checkVersionCompatibility(cwd)\n\n // 2. Load config\n const config = await loadConfig(cwd)\n\n // 3. Check build output exists\n const outDir = resolve(cwd, '.appfunnel')\n const manifestPath = join(outDir, 'manifest.json')\n\n if (!existsSync(manifestPath)) {\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n 'No build output found.',\n \"Run 'appfunnel build' first.\",\n )\n }\n\n // 4. Read manifest\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'))\n const assets: Array<{ path: string; size: number }> = manifest.assets || []\n\n // 5. Read all asset files\n const s = log.spinner('Uploading build...')\n const assetPayloads: Array<{ path: string; content: Buffer; contentType: string }> = []\n\n for (const asset of assets) {\n const fullPath = join(outDir, asset.path)\n if (!existsSync(fullPath)) {\n s.stop()\n throw new CLIError(\n 'BUILD_NOT_FOUND',\n `Build asset missing: ${asset.path}`,\n \"Run 'appfunnel build' to regenerate.\",\n )\n }\n assetPayloads.push({\n path: asset.path,\n content: readFileSync(fullPath),\n contentType: getMimeType(asset.path),\n })\n }\n\n // 6. Publish\n const projectId = config.projectId\n const funnelId = config.funnelId\n\n if (!projectId) {\n s.stop()\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No projectId in appfunnel.config.ts.',\n 'Add projectId to your config. You can find it in the dashboard.',\n )\n }\n\n if (!funnelId) {\n s.stop()\n throw new CLIError(\n 'CONFIG_NOT_FOUND',\n 'No funnelId in appfunnel.config.ts.',\n 'Add funnelId to your config, or create a new funnel from the dashboard.',\n )\n }\n\n const result = await publishBuild(\n projectId,\n funnelId,\n manifest,\n assetPayloads,\n { token: creds.token },\n )\n\n s.stop()\n\n // 7. Print result\n console.log()\n log.success('Published successfully')\n console.log()\n console.log(` ${pc.dim('Build ID:')} ${result.buildId}`)\n console.log(` ${pc.dim('URL:')} ${pc.cyan(result.url)}`)\n console.log(` ${pc.dim('Assets:')} ${assets.length} files`)\n console.log()\n}\n","import { readFileSync } from 'node:fs'\nimport { Command } from 'commander'\nimport pc from 'picocolors'\nimport { CLIError, formatError } from './lib/errors.js'\n\nfunction getCliVersion(): string {\n try {\n const pkg = JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf-8'),\n )\n return pkg.version\n } catch {\n return '0.0.0'\n }\n}\n\nconst program = new Command()\n\nprogram\n .name('appfunnel')\n .description('Build and publish headless AppFunnel projects')\n .version(getCliVersion())\n\nprogram\n .command('init <name>')\n .description('Create a new AppFunnel project')\n .action(async (name: string) => {\n const { initCommand } = await import('./commands/init.js')\n await initCommand(name)\n })\n\nprogram\n .command('login')\n .description('Authenticate with AppFunnel')\n .action(async () => {\n const { loginCommand } = await import('./commands/login.js')\n await loginCommand()\n })\n\nprogram\n .command('whoami')\n .description('Show the currently authenticated user')\n .action(async () => {\n const { whoamiCommand } = await import('./commands/whoami.js')\n await whoamiCommand()\n })\n\nprogram\n .command('dev')\n .description('Start the development server')\n .option('-p, --port <port>', 'Port number', '5173')\n .action(async (options: { port: string }) => {\n const { devCommand } = await import('./commands/dev.js')\n await devCommand({ port: parseInt(options.port, 10) })\n })\n\nprogram\n .command('build')\n .description('Build the funnel for production')\n .action(async () => {\n const { buildCommand } = await import('./commands/build.js')\n await buildCommand()\n })\n\nprogram\n .command('publish')\n .description('Publish the build to AppFunnel')\n .action(async () => {\n const { publishCommand } = await import('./commands/publish.js')\n await publishCommand()\n })\n\n// Global error handler\nprogram.hook('postAction', () => {})\n\nasync function main() {\n try {\n await program.parseAsync(process.argv)\n } catch (err) {\n if (err instanceof CLIError) {\n console.error(formatError(err))\n process.exit(1)\n }\n // Unknown error\n console.error(`${pc.red('ERROR')}: ${err instanceof Error ? err.message : String(err)}`)\n if (err instanceof Error && err.stack) {\n console.error(pc.dim(err.stack))\n }\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":["pc","readFileSync","pc","mkdirSync","writeFileSync","join","pc","resolve","spinner","pc","DEFAULT_API_BASE","existsSync","readFileSync","join","readFileSync","join","readFileSync","existsSync","join","join","resolve","join","existsSync","readFileSync","writeFileSync","join","pc","createServer","resolve","join","readFileSync","writeFileSync","readdirSync","pc","getSdkVersion","DEFAULT_API_BASE","error","resolve","join","readFileSync","existsSync","pc","readFileSync","pc","getCliVersion","initCommand","loginCommand","whoamiCommand","devCommand","buildCommand","publishCommand"]}
|