@posthog/wizard 1.18.2 → 1.20.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.
@@ -0,0 +1,95 @@
1
+ import type { Integration } from './constants';
2
+ import type { WizardOptions } from '../utils/types';
3
+ /**
4
+ * Configuration interface for framework-specific agent integrations.
5
+ * Each framework exports a FrameworkConfig that the universal runner uses.
6
+ */
7
+ export interface FrameworkConfig {
8
+ metadata: FrameworkMetadata;
9
+ detection: FrameworkDetection;
10
+ environment: EnvironmentConfig;
11
+ analytics: AnalyticsConfig;
12
+ prompts: PromptConfig;
13
+ ui: UIConfig;
14
+ }
15
+ /**
16
+ * Basic framework information and documentation
17
+ */
18
+ export interface FrameworkMetadata {
19
+ /** Display name (e.g., "Next.js", "React") */
20
+ name: string;
21
+ /** Integration type from constants */
22
+ integration: Integration;
23
+ /** URL to framework-specific PostHog docs */
24
+ docsUrl: string;
25
+ /** Message shown when user declines AI consent */
26
+ abortMessage: string;
27
+ /**
28
+ * Optional function to gather framework-specific context before agent runs.
29
+ * For Next.js: detects router type
30
+ * For React Native: detects Expo vs bare
31
+ */
32
+ gatherContext?: (options: WizardOptions) => Promise<Record<string, any>>;
33
+ }
34
+ /**
35
+ * Framework detection and version handling
36
+ */
37
+ export interface FrameworkDetection {
38
+ /** Package name to check in package.json (e.g., "next", "react") */
39
+ packageName: string;
40
+ /** Human-readable name for error messages (e.g., "Next.js") */
41
+ packageDisplayName: string;
42
+ /** Extract version from package.json */
43
+ getVersion: (packageJson: any) => string | undefined;
44
+ /** Optional: Convert version to analytics bucket (e.g., "15.x") */
45
+ getVersionBucket?: (version: string) => string;
46
+ }
47
+ /**
48
+ * Environment variable configuration
49
+ */
50
+ export interface EnvironmentConfig {
51
+ /** Whether to upload env vars to hosting providers post-agent */
52
+ uploadToHosting: boolean;
53
+ /**
54
+ * Build the environment variables object for this framework.
55
+ * Returns the exact variable names and values to upload to hosting providers.
56
+ */
57
+ getEnvVars: (apiKey: string, host: string) => Record<string, string>;
58
+ }
59
+ /**
60
+ * Analytics configuration
61
+ */
62
+ export interface AnalyticsConfig {
63
+ /** Generate tags from context (e.g., { 'nextjs-version': '15.x', 'router': 'app' }) */
64
+ getTags: (context: any) => Record<string, any>;
65
+ /** Optional: Additional event properties */
66
+ getEventProperties?: (context: any) => Record<string, any>;
67
+ }
68
+ /**
69
+ * Prompt configuration
70
+ */
71
+ export interface PromptConfig {
72
+ /**
73
+ * Optional: Additional context lines to append to base prompt
74
+ * For Next.js: "- Router: app"
75
+ * For React Native: "- Platform: Expo"
76
+ */
77
+ getAdditionalContextLines?: (context: any) => string[];
78
+ }
79
+ /**
80
+ * UI messaging configuration
81
+ */
82
+ export interface UIConfig {
83
+ /** Welcome message for wizard start */
84
+ welcomeMessage: string;
85
+ /** Spinner message while agent runs */
86
+ spinnerMessage: string;
87
+ /** Success message when agent completes */
88
+ successMessage: string;
89
+ /** Estimated time for agent to complete (in minutes) */
90
+ estimatedDurationMinutes: number;
91
+ /** Generate "What the agent did" bullets from context */
92
+ getOutroChanges: (context: any) => string[];
93
+ /** Generate "Next steps" bullets from context */
94
+ getOutroNextSteps: (context: any) => string[];
95
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=framework-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-config.js","sourceRoot":"","sources":["../../../src/lib/framework-config.ts"],"names":[],"mappings":"","sourcesContent":["import type { Integration } from './constants';\nimport type { WizardOptions } from '../utils/types';\n\n/**\n * Configuration interface for framework-specific agent integrations.\n * Each framework exports a FrameworkConfig that the universal runner uses.\n */\nexport interface FrameworkConfig {\n metadata: FrameworkMetadata;\n detection: FrameworkDetection;\n environment: EnvironmentConfig;\n analytics: AnalyticsConfig;\n prompts: PromptConfig;\n ui: UIConfig;\n}\n\n/**\n * Basic framework information and documentation\n */\nexport interface FrameworkMetadata {\n /** Display name (e.g., \"Next.js\", \"React\") */\n name: string;\n\n /** Integration type from constants */\n integration: Integration;\n\n /** URL to framework-specific PostHog docs */\n docsUrl: string;\n\n /** Message shown when user declines AI consent */\n abortMessage: string;\n\n /**\n * Optional function to gather framework-specific context before agent runs.\n * For Next.js: detects router type\n * For React Native: detects Expo vs bare\n */\n gatherContext?: (options: WizardOptions) => Promise<Record<string, any>>;\n}\n\n/**\n * Framework detection and version handling\n */\nexport interface FrameworkDetection {\n /** Package name to check in package.json (e.g., \"next\", \"react\") */\n packageName: string;\n\n /** Human-readable name for error messages (e.g., \"Next.js\") */\n packageDisplayName: string;\n\n /** Extract version from package.json */\n getVersion: (packageJson: any) => string | undefined;\n\n /** Optional: Convert version to analytics bucket (e.g., \"15.x\") */\n getVersionBucket?: (version: string) => string;\n}\n\n/**\n * Environment variable configuration\n */\nexport interface EnvironmentConfig {\n /** Whether to upload env vars to hosting providers post-agent */\n uploadToHosting: boolean;\n\n /**\n * Build the environment variables object for this framework.\n * Returns the exact variable names and values to upload to hosting providers.\n */\n getEnvVars: (apiKey: string, host: string) => Record<string, string>;\n}\n\n/**\n * Analytics configuration\n */\nexport interface AnalyticsConfig {\n /** Generate tags from context (e.g., { 'nextjs-version': '15.x', 'router': 'app' }) */\n getTags: (context: any) => Record<string, any>;\n\n /** Optional: Additional event properties */\n getEventProperties?: (context: any) => Record<string, any>;\n}\n\n/**\n * Prompt configuration\n */\nexport interface PromptConfig {\n /**\n * Optional: Additional context lines to append to base prompt\n * For Next.js: \"- Router: app\"\n * For React Native: \"- Platform: Expo\"\n */\n getAdditionalContextLines?: (context: any) => string[];\n}\n\n/**\n * UI messaging configuration\n */\nexport interface UIConfig {\n /** Welcome message for wizard start */\n welcomeMessage: string;\n\n /** Spinner message while agent runs */\n spinnerMessage: string;\n\n /** Success message when agent completes */\n successMessage: string;\n\n /** Estimated time for agent to complete (in minutes) */\n estimatedDurationMinutes: number;\n\n /** Generate \"What the agent did\" bullets from context */\n getOutroChanges: (context: any) => string[];\n\n /** Generate \"Next steps\" bullets from context */\n getOutroNextSteps: (context: any) => string[];\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { WizardOptions } from '../utils/types';
2
2
  /**
3
- * Simplified Next.js wizard that delegates to PostHog MCP's /integrate command
3
+ * Next.js wizard powered by the universal agent runner.
4
4
  */
5
5
  export declare function runNextjsWizardAgent(options: WizardOptions): Promise<void>;
@@ -1,146 +1,82 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.runNextjsWizardAgent = runNextjsWizardAgent;
7
- /* Simplified Next.js wizard using posthog-agent with PostHog MCP */
8
- const clack_utils_1 = require("../utils/clack-utils");
4
+ const debug_1 = require("../utils/debug");
5
+ const agent_runner_1 = require("../lib/agent-runner");
6
+ const constants_1 = require("../lib/constants");
9
7
  const package_json_1 = require("../utils/package-json");
10
8
  const utils_1 = require("./utils");
11
- const clack_1 = __importDefault(require("../utils/clack"));
12
- const constants_1 = require("../lib/constants");
13
- const analytics_1 = require("../utils/analytics");
14
- const clack_utils_2 = require("../utils/clack-utils");
15
- const urls_1 = require("../utils/urls");
16
- const chalk_1 = __importDefault(require("chalk"));
17
- const steps_1 = require("../steps");
18
- const debug_1 = require("../utils/debug");
19
- const agent_interface_1 = require("../lib/agent-interface");
20
9
  /**
21
- * Simplified Next.js wizard that delegates to PostHog MCP's /integrate command
10
+ * Next.js framework configuration for the universal agent runner.
11
+ */
12
+ const NEXTJS_AGENT_CONFIG = {
13
+ metadata: {
14
+ name: 'Next.js',
15
+ integration: constants_1.Integration.nextjs,
16
+ docsUrl: 'https://posthog.com/docs/libraries/next-js',
17
+ abortMessage: 'This wizard uses an LLM agent to intelligently modify your project. Please view the docs to setup Next.js manually instead: https://posthog.com/docs/libraries/next-js',
18
+ gatherContext: async (options) => {
19
+ const router = await (0, utils_1.getNextJsRouter)(options);
20
+ return { router };
21
+ },
22
+ },
23
+ detection: {
24
+ packageName: 'next',
25
+ packageDisplayName: 'Next.js',
26
+ getVersion: (packageJson) => (0, package_json_1.getPackageVersion)('next', packageJson),
27
+ getVersionBucket: utils_1.getNextJsVersionBucket,
28
+ },
29
+ environment: {
30
+ uploadToHosting: true,
31
+ getEnvVars: (apiKey, host) => ({
32
+ NEXT_PUBLIC_POSTHOG_KEY: apiKey,
33
+ NEXT_PUBLIC_POSTHOG_HOST: host,
34
+ }),
35
+ },
36
+ analytics: {
37
+ getTags: (context) => {
38
+ const router = context.router;
39
+ return {
40
+ router: router === utils_1.NextJsRouter.APP_ROUTER ? 'app' : 'pages',
41
+ };
42
+ },
43
+ },
44
+ prompts: {
45
+ getAdditionalContextLines: (context) => {
46
+ const router = context.router;
47
+ const routerType = router === utils_1.NextJsRouter.APP_ROUTER ? 'app' : 'pages';
48
+ return [`Router: ${routerType}`];
49
+ },
50
+ },
51
+ ui: {
52
+ welcomeMessage: 'PostHog Next.js wizard (agent-powered)',
53
+ spinnerMessage: 'Writing your PostHog setup with events, error capture and more...',
54
+ successMessage: 'PostHog integration complete',
55
+ estimatedDurationMinutes: 8,
56
+ getOutroChanges: (context) => {
57
+ const router = context.router;
58
+ const routerName = (0, utils_1.getNextJsRouterName)(router);
59
+ return [
60
+ `Analyzed your Next.js project structure (${routerName})`,
61
+ `Created and configured PostHog initializers`,
62
+ `Integrated PostHog into your application`,
63
+ ];
64
+ },
65
+ getOutroNextSteps: () => {
66
+ return [
67
+ 'Start your development server to see PostHog in action',
68
+ 'Visit your PostHog dashboard to see incoming events',
69
+ ];
70
+ },
71
+ },
72
+ };
73
+ /**
74
+ * Next.js wizard powered by the universal agent runner.
22
75
  */
23
76
  async function runNextjsWizardAgent(options) {
24
77
  if (options.debug) {
25
78
  (0, debug_1.enableDebugLogs)();
26
79
  }
27
- (0, clack_utils_1.printWelcome)({
28
- wizardName: 'PostHog Next.js wizard (agent-powered)',
29
- });
30
- clack_1.default.log.info('🧙 The wizard has chosen you to try the next-generation agent integration for Next.js.\n\nStand by for the good stuff, and let me know how it goes:\n\ndanilo@posthog.com');
31
- const aiConsent = await (0, clack_utils_1.askForAIConsent)(options);
32
- if (!aiConsent) {
33
- await (0, clack_utils_1.abort)('This wizard uses an LLM agent to intelligently modify your project. Please view the docs to setup Next.js manually instead: https://posthog.com/docs/libraries/next-js', 0);
34
- }
35
- const cloudRegion = options.cloudRegion ?? (await (0, clack_utils_2.askForCloudRegion)());
36
- const typeScriptDetected = (0, clack_utils_1.isUsingTypeScript)(options);
37
- await (0, clack_utils_1.confirmContinueIfNoOrDirtyGitRepo)(options);
38
- const packageJson = await (0, clack_utils_1.getPackageDotJson)(options);
39
- await (0, clack_utils_1.ensurePackageIsInstalled)(packageJson, 'next', 'Next.js');
40
- const nextVersion = (0, package_json_1.getPackageVersion)('next', packageJson);
41
- analytics_1.analytics.setTag('nextjs-version', (0, utils_1.getNextJsVersionBucket)(nextVersion));
42
- analytics_1.analytics.capture(constants_1.WIZARD_INTERACTION_EVENT_NAME, {
43
- action: 'started agent integration',
44
- });
45
- const { projectApiKey, host, accessToken } = await (0, clack_utils_1.getOrAskForProjectData)({
46
- ...options,
47
- cloudRegion,
48
- });
49
- const router = await (0, utils_1.getNextJsRouter)(options);
50
- const routerType = router === utils_1.NextJsRouter.APP_ROUTER ? 'app' : 'pages';
51
- const spinner = clack_1.default.spinner();
52
- const agent = (0, agent_interface_1.initializeAgent)({
53
- workingDirectory: options.installDir,
54
- posthogMcpUrl: 'https://mcp.posthog.com/mcp',
55
- posthogApiKey: accessToken,
56
- debug: false,
57
- }, options, spinner);
58
- const integrationPrompt = buildIntegrationPrompt({
59
- framework: 'Next.js',
60
- version: nextVersion || 'latest',
61
- router: routerType,
62
- typescript: typeScriptDetected,
63
- projectApiKey,
64
- host,
65
- });
66
- await (0, agent_interface_1.runAgent)(agent, integrationPrompt, options, spinner, {
67
- estimatedDurationMinutes: 8,
68
- spinnerMessage: 'Writing your PostHog setup with events, error capture and more...',
69
- successMessage: 'PostHog integration complete',
70
- errorMessage: 'Integration failed',
71
- });
72
- const { relativeEnvFilePath, addedEnvVariables } = await (0, steps_1.addOrUpdateEnvironmentVariablesStep)({
73
- variables: {
74
- NEXT_PUBLIC_POSTHOG_KEY: projectApiKey,
75
- NEXT_PUBLIC_POSTHOG_HOST: host,
76
- },
77
- installDir: options.installDir,
78
- integration: constants_1.Integration.nextjs,
79
- });
80
- const uploadedEnvVars = await (0, steps_1.uploadEnvironmentVariablesStep)({
81
- NEXT_PUBLIC_POSTHOG_KEY: projectApiKey,
82
- NEXT_PUBLIC_POSTHOG_HOST: host,
83
- }, {
84
- integration: constants_1.Integration.nextjs,
85
- options,
86
- });
87
- await (0, steps_1.addMCPServerToClientsStep)({
88
- cloudRegion,
89
- integration: constants_1.Integration.nextjs,
90
- });
91
- const continueUrl = options.signup
92
- ? `${(0, urls_1.getCloudUrlFromRegion)(cloudRegion)}/products?source=wizard`
93
- : undefined;
94
- const changes = [
95
- addedEnvVariables
96
- ? `Added your Project API key to your ${relativeEnvFilePath} file`
97
- : '',
98
- uploadedEnvVars.length > 0
99
- ? `Uploaded your Project API key to your hosting provider`
100
- : '',
101
- ].filter(Boolean);
102
- const nextSteps = [
103
- uploadedEnvVars.length === 0
104
- ? `Upload your Project API key to your hosting provider`
105
- : '',
106
- ].filter(Boolean);
107
- const outroMessage = `
108
- ${chalk_1.default.green('Successfully installed PostHog!')}
109
-
110
- ${chalk_1.default.cyan('What the agent did:')}
111
- • Analyzed your Next.js project structure (${routerType} router)
112
- • Created and configured PostHog initializers
113
- • Integrated PostHog into your application
114
- ${changes.map((change) => `• ${change}`).join('\n')}
115
-
116
- ${chalk_1.default.yellow('Next steps:')}
117
- • Start your development server to see PostHog in action
118
- • Visit your PostHog dashboard to see incoming events
119
- ${nextSteps.map((step) => `• ${step}`).join('\n')}
120
-
121
- Learn more about PostHog + Next.js: ${chalk_1.default.cyan('https://posthog.com/docs/libraries/next-js')}
122
- ${continueUrl ? `\nContinue onboarding: ${chalk_1.default.cyan(continueUrl)}\n` : ``}
123
- ${chalk_1.default.dim('Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made.')}
124
-
125
- ${chalk_1.default.dim(`How did this work for you? Drop me a line: danilo@posthog.com`)}`;
126
- clack_1.default.outro(outroMessage);
127
- await analytics_1.analytics.shutdown('success');
128
- }
129
- function buildIntegrationPrompt(context) {
130
- return `You have access to the PostHog MCP server which provides an integration resource to integrate PostHog into this ${context.framework} project.
131
-
132
- Project context:
133
- - Framework: ${context.framework} ${context.version}
134
- - Router: ${context.router}
135
- - TypeScript: ${context.typescript ? 'Yes' : 'No'}
136
- - PostHog API Key: ${context.projectApiKey}
137
- - PostHog Host: ${context.host}
138
-
139
- Instructions:
140
- 1. Call the PostHog MCP's resource for setup: posthog://integration/workflow/setup/begin
141
- 2. Follow all instructions provided
142
-
143
- The PostHog MCP will provide specific integration code and instructions. Please follow them carefully. Be sure to look for lockfiles to determine the appropriate package manager to use when installing PostHog. Do not manually edit the package.json file.
144
- `;
80
+ await (0, agent_runner_1.runAgentWizard)(NEXTJS_AGENT_CONFIG, options);
145
81
  }
146
82
  //# sourceMappingURL=nextjs-wizard-agent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs-wizard-agent.js","sourceRoot":"","sources":["../../../src/nextjs/nextjs-wizard-agent.ts"],"names":[],"mappings":"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","sourcesContent":["/* Simplified Next.js wizard using posthog-agent with PostHog MCP */\nimport {\n abort,\n askForAIConsent,\n confirmContinueIfNoOrDirtyGitRepo,\n ensurePackageIsInstalled,\n getOrAskForProjectData,\n getPackageDotJson,\n isUsingTypeScript,\n printWelcome,\n} from '../utils/clack-utils';\nimport { getPackageVersion } from '../utils/package-json';\nimport { getNextJsRouter, getNextJsVersionBucket, NextJsRouter } from './utils';\nimport clack from '../utils/clack';\nimport { Integration, WIZARD_INTERACTION_EVENT_NAME } from '../lib/constants';\nimport { analytics } from '../utils/analytics';\nimport type { WizardOptions } from '../utils/types';\nimport { askForCloudRegion } from '../utils/clack-utils';\nimport { getCloudUrlFromRegion } from '../utils/urls';\nimport chalk from 'chalk';\nimport {\n addOrUpdateEnvironmentVariablesStep,\n addMCPServerToClientsStep,\n uploadEnvironmentVariablesStep,\n} from '../steps';\nimport { enableDebugLogs } from '../utils/debug';\nimport { initializeAgent, runAgent } from '../lib/agent-interface';\n\n/**\n * Simplified Next.js wizard that delegates to PostHog MCP's /integrate command\n */\nexport async function runNextjsWizardAgent(\n options: WizardOptions,\n): Promise<void> {\n if (options.debug) {\n enableDebugLogs();\n }\n\n printWelcome({\n wizardName: 'PostHog Next.js wizard (agent-powered)',\n });\n\n clack.log.info(\n '🧙 The wizard has chosen you to try the next-generation agent integration for Next.js.\\n\\nStand by for the good stuff, and let me know how it goes:\\n\\ndanilo@posthog.com',\n );\n\n const aiConsent = await askForAIConsent(options);\n\n if (!aiConsent) {\n await abort(\n 'This wizard uses an LLM agent to intelligently modify your project. Please view the docs to setup Next.js manually instead: https://posthog.com/docs/libraries/next-js',\n 0,\n );\n }\n\n const cloudRegion = options.cloudRegion ?? (await askForCloudRegion());\n const typeScriptDetected = isUsingTypeScript(options);\n\n await confirmContinueIfNoOrDirtyGitRepo(options);\n\n const packageJson = await getPackageDotJson(options);\n await ensurePackageIsInstalled(packageJson, 'next', 'Next.js');\n\n const nextVersion = getPackageVersion('next', packageJson);\n analytics.setTag('nextjs-version', getNextJsVersionBucket(nextVersion));\n\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'started agent integration',\n });\n\n const { projectApiKey, host, accessToken } = await getOrAskForProjectData({\n ...options,\n cloudRegion,\n });\n\n const router = await getNextJsRouter(options);\n const routerType = router === NextJsRouter.APP_ROUTER ? 'app' : 'pages';\n\n const spinner = clack.spinner();\n\n const agent = initializeAgent(\n {\n workingDirectory: options.installDir,\n posthogMcpUrl: 'https://mcp.posthog.com/mcp',\n posthogApiKey: accessToken,\n debug: false,\n },\n options,\n spinner,\n );\n\n const integrationPrompt = buildIntegrationPrompt({\n framework: 'Next.js',\n version: nextVersion || 'latest',\n router: routerType,\n typescript: typeScriptDetected,\n projectApiKey,\n host,\n });\n\n await runAgent(agent, integrationPrompt, options, spinner, {\n estimatedDurationMinutes: 8,\n spinnerMessage:\n 'Writing your PostHog setup with events, error capture and more...',\n successMessage: 'PostHog integration complete',\n errorMessage: 'Integration failed',\n });\n\n const { relativeEnvFilePath, addedEnvVariables } =\n await addOrUpdateEnvironmentVariablesStep({\n variables: {\n NEXT_PUBLIC_POSTHOG_KEY: projectApiKey,\n NEXT_PUBLIC_POSTHOG_HOST: host,\n },\n installDir: options.installDir,\n integration: Integration.nextjs,\n });\n\n const uploadedEnvVars = await uploadEnvironmentVariablesStep(\n {\n NEXT_PUBLIC_POSTHOG_KEY: projectApiKey,\n NEXT_PUBLIC_POSTHOG_HOST: host,\n },\n {\n integration: Integration.nextjs,\n options,\n },\n );\n\n await addMCPServerToClientsStep({\n cloudRegion,\n integration: Integration.nextjs,\n });\n\n const continueUrl = options.signup\n ? `${getCloudUrlFromRegion(cloudRegion)}/products?source=wizard`\n : undefined;\n\n const changes = [\n addedEnvVariables\n ? `Added your Project API key to your ${relativeEnvFilePath} file`\n : '',\n uploadedEnvVars.length > 0\n ? `Uploaded your Project API key to your hosting provider`\n : '',\n ].filter(Boolean);\n\n const nextSteps = [\n uploadedEnvVars.length === 0\n ? `Upload your Project API key to your hosting provider`\n : '',\n ].filter(Boolean);\n\n const outroMessage = `\n${chalk.green('Successfully installed PostHog!')}\n\n${chalk.cyan('What the agent did:')}\n• Analyzed your Next.js project structure (${routerType} router)\n• Created and configured PostHog initializers\n• Integrated PostHog into your application\n${changes.map((change) => `• ${change}`).join('\\n')}\n\n${chalk.yellow('Next steps:')}\n• Start your development server to see PostHog in action\n• Visit your PostHog dashboard to see incoming events\n${nextSteps.map((step) => `• ${step}`).join('\\n')}\n\nLearn more about PostHog + Next.js: ${chalk.cyan(\n 'https://posthog.com/docs/libraries/next-js',\n )}\n${continueUrl ? `\\nContinue onboarding: ${chalk.cyan(continueUrl)}\\n` : ``}\n${chalk.dim(\n 'Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made.',\n)}\n\n${chalk.dim(`How did this work for you? Drop me a line: danilo@posthog.com`)}`;\n\n clack.outro(outroMessage);\n\n await analytics.shutdown('success');\n}\n\nfunction buildIntegrationPrompt(context: {\n framework: string;\n version: string;\n router: string;\n typescript: boolean;\n projectApiKey: string;\n host: string;\n}): string {\n return `You have access to the PostHog MCP server which provides an integration resource to integrate PostHog into this ${\n context.framework\n } project.\n\nProject context:\n- Framework: ${context.framework} ${context.version}\n- Router: ${context.router}\n- TypeScript: ${context.typescript ? 'Yes' : 'No'}\n- PostHog API Key: ${context.projectApiKey}\n- PostHog Host: ${context.host}\n\nInstructions:\n1. Call the PostHog MCP's resource for setup: posthog://integration/workflow/setup/begin\n2. Follow all instructions provided\n\nThe PostHog MCP will provide specific integration code and instructions. Please follow them carefully. Be sure to look for lockfiles to determine the appropriate package manager to use when installing PostHog. Do not manually edit the package.json file.\n`;\n}\n"]}
1
+ {"version":3,"file":"nextjs-wizard-agent.js","sourceRoot":"","sources":["../../../src/nextjs/nextjs-wizard-agent.ts"],"names":[],"mappings":";;AAyFA,oDAQC;AA9FD,0CAAiD;AACjD,sDAAqD;AACrD,gDAA+C;AAC/C,wDAA0D;AAC1D,mCAKiB;AAEjB;;GAEG;AACH,MAAM,mBAAmB,GAAoB;IAC3C,QAAQ,EAAE;QACR,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,uBAAW,CAAC,MAAM;QAC/B,OAAO,EAAE,4CAA4C;QACrD,YAAY,EACV,wKAAwK;QAC1K,aAAa,EAAE,KAAK,EAAE,OAAsB,EAAE,EAAE;YAC9C,MAAM,MAAM,GAAG,MAAM,IAAA,uBAAe,EAAC,OAAO,CAAC,CAAC;YAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,CAAC;KACF;IAED,SAAS,EAAE;QACT,WAAW,EAAE,MAAM;QACnB,kBAAkB,EAAE,SAAS;QAC7B,UAAU,EAAE,CAAC,WAAgB,EAAE,EAAE,CAAC,IAAA,gCAAiB,EAAC,MAAM,EAAE,WAAW,CAAC;QACxE,gBAAgB,EAAE,8BAAsB;KACzC;IAED,WAAW,EAAE;QACX,eAAe,EAAE,IAAI;QACrB,UAAU,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7B,uBAAuB,EAAE,MAAM;YAC/B,wBAAwB,EAAE,IAAI;SAC/B,CAAC;KACH;IAED,SAAS,EAAE;QACT,OAAO,EAAE,CAAC,OAAY,EAAE,EAAE;YACxB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAsB,CAAC;YAC9C,OAAO;gBACL,MAAM,EAAE,MAAM,KAAK,oBAAY,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;aAC7D,CAAC;QACJ,CAAC;KACF;IAED,OAAO,EAAE;QACP,yBAAyB,EAAE,CAAC,OAAY,EAAE,EAAE;YAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAsB,CAAC;YAC9C,MAAM,UAAU,GAAG,MAAM,KAAK,oBAAY,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YACxE,OAAO,CAAC,WAAW,UAAU,EAAE,CAAC,CAAC;QACnC,CAAC;KACF;IAED,EAAE,EAAE;QACF,cAAc,EAAE,wCAAwC;QACxD,cAAc,EACZ,mEAAmE;QACrE,cAAc,EAAE,8BAA8B;QAC9C,wBAAwB,EAAE,CAAC;QAC3B,eAAe,EAAE,CAAC,OAAY,EAAE,EAAE;YAChC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAsB,CAAC;YAC9C,MAAM,UAAU,GAAG,IAAA,2BAAmB,EAAC,MAAM,CAAC,CAAC;YAC/C,OAAO;gBACL,4CAA4C,UAAU,GAAG;gBACzD,6CAA6C;gBAC7C,0CAA0C;aAC3C,CAAC;QACJ,CAAC;QACD,iBAAiB,EAAE,GAAG,EAAE;YACtB,OAAO;gBACL,wDAAwD;gBACxD,qDAAqD;aACtD,CAAC;QACJ,CAAC;KACF;CACF,CAAC;AAEF;;GAEG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAsB;IAEtB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAA,uBAAe,GAAE,CAAC;IACpB,CAAC;IAED,MAAM,IAAA,6BAAc,EAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC","sourcesContent":["/* Simplified Next.js wizard using posthog-agent with PostHog MCP */\nimport type { WizardOptions } from '../utils/types';\nimport type { FrameworkConfig } from '../lib/framework-config';\nimport { enableDebugLogs } from '../utils/debug';\nimport { runAgentWizard } from '../lib/agent-runner';\nimport { Integration } from '../lib/constants';\nimport { getPackageVersion } from '../utils/package-json';\nimport {\n getNextJsRouter,\n getNextJsVersionBucket,\n getNextJsRouterName,\n NextJsRouter,\n} from './utils';\n\n/**\n * Next.js framework configuration for the universal agent runner.\n */\nconst NEXTJS_AGENT_CONFIG: FrameworkConfig = {\n metadata: {\n name: 'Next.js',\n integration: Integration.nextjs,\n docsUrl: 'https://posthog.com/docs/libraries/next-js',\n abortMessage:\n 'This wizard uses an LLM agent to intelligently modify your project. Please view the docs to setup Next.js manually instead: https://posthog.com/docs/libraries/next-js',\n gatherContext: async (options: WizardOptions) => {\n const router = await getNextJsRouter(options);\n return { router };\n },\n },\n\n detection: {\n packageName: 'next',\n packageDisplayName: 'Next.js',\n getVersion: (packageJson: any) => getPackageVersion('next', packageJson),\n getVersionBucket: getNextJsVersionBucket,\n },\n\n environment: {\n uploadToHosting: true,\n getEnvVars: (apiKey, host) => ({\n NEXT_PUBLIC_POSTHOG_KEY: apiKey,\n NEXT_PUBLIC_POSTHOG_HOST: host,\n }),\n },\n\n analytics: {\n getTags: (context: any) => {\n const router = context.router as NextJsRouter;\n return {\n router: router === NextJsRouter.APP_ROUTER ? 'app' : 'pages',\n };\n },\n },\n\n prompts: {\n getAdditionalContextLines: (context: any) => {\n const router = context.router as NextJsRouter;\n const routerType = router === NextJsRouter.APP_ROUTER ? 'app' : 'pages';\n return [`Router: ${routerType}`];\n },\n },\n\n ui: {\n welcomeMessage: 'PostHog Next.js wizard (agent-powered)',\n spinnerMessage:\n 'Writing your PostHog setup with events, error capture and more...',\n successMessage: 'PostHog integration complete',\n estimatedDurationMinutes: 8,\n getOutroChanges: (context: any) => {\n const router = context.router as NextJsRouter;\n const routerName = getNextJsRouterName(router);\n return [\n `Analyzed your Next.js project structure (${routerName})`,\n `Created and configured PostHog initializers`,\n `Integrated PostHog into your application`,\n ];\n },\n getOutroNextSteps: () => {\n return [\n 'Start your development server to see PostHog in action',\n 'Visit your PostHog dashboard to see incoming events',\n ];\n },\n },\n};\n\n/**\n * Next.js wizard powered by the universal agent runner.\n */\nexport async function runNextjsWizardAgent(\n options: WizardOptions,\n): Promise<void> {\n if (options.debug) {\n enableDebugLogs();\n }\n\n await runAgentWizard(NEXTJS_AGENT_CONFIG, options);\n}\n"]}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const analytics_1 = require("../analytics");
4
4
  const posthog_node_1 = require("posthog-node");
5
5
  const uuid_1 = require("uuid");
6
+ const constants_1 = require("../../lib/constants");
6
7
  jest.mock('posthog-node');
7
8
  jest.mock('uuid');
8
9
  const mockUuidv4 = uuid_1.v4;
@@ -28,7 +29,7 @@ describe('Analytics', () => {
28
29
  const properties = { integration: 'nextjs' };
29
30
  analytics.captureException(error, properties);
30
31
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
31
- team: 'growth',
32
+ team: constants_1.ANALYTICS_TEAM_TAG,
32
33
  $app_name: 'wizard',
33
34
  ...properties,
34
35
  });
@@ -39,7 +40,7 @@ describe('Analytics', () => {
39
40
  analytics.setTag('testTag', 'testValue');
40
41
  analytics.captureException(error, properties);
41
42
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
42
- team: 'growth',
43
+ team: constants_1.ANALYTICS_TEAM_TAG,
43
44
  $app_name: 'wizard',
44
45
  testTag: 'testValue',
45
46
  ...properties,
@@ -51,7 +52,7 @@ describe('Analytics', () => {
51
52
  analytics.setDistinctId(distinctId);
52
53
  analytics.captureException(error);
53
54
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, distinctId, {
54
- team: 'growth',
55
+ team: constants_1.ANALYTICS_TEAM_TAG,
55
56
  $app_name: 'wizard',
56
57
  });
57
58
  });
@@ -59,7 +60,7 @@ describe('Analytics', () => {
59
60
  const error = new Error('Test error');
60
61
  analytics.captureException(error);
61
62
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
62
- team: 'growth',
63
+ team: constants_1.ANALYTICS_TEAM_TAG,
63
64
  $app_name: 'wizard',
64
65
  });
65
66
  });
@@ -70,7 +71,7 @@ describe('Analytics', () => {
70
71
  analytics.setTag('version', '1.0.0');
71
72
  analytics.captureException(error, properties);
72
73
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
73
- team: 'growth',
74
+ team: constants_1.ANALYTICS_TEAM_TAG,
74
75
  $app_name: 'wizard',
75
76
  environment: 'test',
76
77
  version: '1.0.0',
@@ -84,16 +85,16 @@ describe('Analytics', () => {
84
85
  analytics.setTag('integration', 'nextjs');
85
86
  analytics.captureException(error, properties);
86
87
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
87
- team: 'growth',
88
+ team: constants_1.ANALYTICS_TEAM_TAG,
88
89
  $app_name: 'wizard',
89
90
  integration: 'react',
90
91
  });
91
92
  });
92
- it('should always include team:growth property in exceptions', () => {
93
+ it('should always include team property in exceptions', () => {
93
94
  const error = new Error('Test error');
94
95
  analytics.captureException(error);
95
96
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
96
- team: 'growth',
97
+ team: constants_1.ANALYTICS_TEAM_TAG,
97
98
  $app_name: 'wizard',
98
99
  });
99
100
  });
@@ -109,7 +110,7 @@ describe('Analytics', () => {
109
110
  step: 'wizard-execution',
110
111
  });
111
112
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, 'test-uuid', {
112
- team: 'growth',
113
+ team: constants_1.ANALYTICS_TEAM_TAG,
113
114
  $app_name: 'wizard',
114
115
  integration: 'nextjs',
115
116
  forceInstall: true,
@@ -125,7 +126,7 @@ describe('Analytics', () => {
125
126
  analytics.setTag('integration', 'svelte');
126
127
  analytics.captureException(error);
127
128
  expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(error, distinctId, {
128
- team: 'growth',
129
+ team: constants_1.ANALYTICS_TEAM_TAG,
129
130
  $app_name: 'wizard',
130
131
  integration: 'svelte',
131
132
  });
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.test.js","sourceRoot":"","sources":["../../../../src/utils/__tests__/analytics.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Analytics } from '../analytics';\nimport { PostHog } from 'posthog-node';\nimport { v4 as uuidv4 } from 'uuid';\n\njest.mock('posthog-node');\njest.mock('uuid');\n\nconst mockUuidv4 = uuidv4 as jest.MockedFunction<typeof uuidv4>;\nconst MockedPostHog = PostHog as jest.MockedClass<typeof PostHog>;\n\ndescribe('Analytics', () => {\n let analytics: Analytics;\n let mockPostHogInstance: jest.Mocked<PostHog>;\n\n beforeEach(() => {\n jest.clearAllMocks();\n mockUuidv4.mockReturnValue('test-uuid' as any);\n\n mockPostHogInstance = {\n capture: jest.fn(),\n captureException: jest.fn(),\n alias: jest.fn(),\n shutdown: jest.fn().mockResolvedValue(undefined),\n } as any;\n\n MockedPostHog.mockImplementation(() => mockPostHogInstance);\n\n analytics = new Analytics();\n });\n\n describe('captureException', () => {\n it('should capture exception with error object and properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs' };\n\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n ...properties,\n },\n );\n });\n\n it('should capture exception with tags included in properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs' };\n\n analytics.setTag('testTag', 'testValue');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n testTag: 'testValue',\n ...properties,\n },\n );\n });\n\n it('should capture exception with distinct ID when set', () => {\n const error = new Error('Test error');\n const distinctId = 'user-123';\n\n analytics.setDistinctId(distinctId);\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n distinctId,\n {\n team: 'growth',\n $app_name: 'wizard',\n },\n );\n });\n\n it('should capture exception without properties when not provided', () => {\n const error = new Error('Test error');\n\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n },\n );\n });\n\n it('should merge tags with provided properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs', step: 'installation' };\n\n analytics.setTag('environment', 'test');\n analytics.setTag('version', '1.0.0');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n environment: 'test',\n version: '1.0.0',\n integration: 'nextjs',\n step: 'installation',\n },\n );\n });\n\n it('should override tags with properties when keys conflict', () => {\n const error = new Error('Test error');\n const properties = { integration: 'react' };\n\n analytics.setTag('integration', 'nextjs');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n integration: 'react',\n },\n );\n });\n\n it('should always include team:growth property in exceptions', () => {\n const error = new Error('Test error');\n\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n },\n );\n });\n });\n\n describe('integration with other methods', () => {\n it('should work correctly with setTag and captureException', () => {\n const error = new Error('Test error');\n\n analytics.setTag('integration', 'nextjs');\n analytics.setTag('forceInstall', true);\n analytics.setTag('debug', false);\n\n analytics.captureException(error, {\n arguments: JSON.stringify({ installDir: '/test' }),\n step: 'wizard-execution',\n });\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: 'growth',\n $app_name: 'wizard',\n integration: 'nextjs',\n forceInstall: true,\n debug: false,\n arguments: JSON.stringify({ installDir: '/test' }),\n step: 'wizard-execution',\n },\n );\n });\n\n it('should work correctly with setDistinctId and captureException', () => {\n const error = new Error('Test error');\n const distinctId = 'user-456';\n\n analytics.setDistinctId(distinctId);\n analytics.setTag('integration', 'svelte');\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n distinctId,\n {\n team: 'growth',\n $app_name: 'wizard',\n integration: 'svelte',\n },\n );\n });\n });\n});\n"]}
1
+ {"version":3,"file":"analytics.test.js","sourceRoot":"","sources":["../../../../src/utils/__tests__/analytics.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Analytics } from '../analytics';\nimport { PostHog } from 'posthog-node';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ANALYTICS_TEAM_TAG } from '../../lib/constants';\n\njest.mock('posthog-node');\njest.mock('uuid');\n\nconst mockUuidv4 = uuidv4 as jest.MockedFunction<typeof uuidv4>;\nconst MockedPostHog = PostHog as jest.MockedClass<typeof PostHog>;\n\ndescribe('Analytics', () => {\n let analytics: Analytics;\n let mockPostHogInstance: jest.Mocked<PostHog>;\n\n beforeEach(() => {\n jest.clearAllMocks();\n mockUuidv4.mockReturnValue('test-uuid' as any);\n\n mockPostHogInstance = {\n capture: jest.fn(),\n captureException: jest.fn(),\n alias: jest.fn(),\n shutdown: jest.fn().mockResolvedValue(undefined),\n } as any;\n\n MockedPostHog.mockImplementation(() => mockPostHogInstance);\n\n analytics = new Analytics();\n });\n\n describe('captureException', () => {\n it('should capture exception with error object and properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs' };\n\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n ...properties,\n },\n );\n });\n\n it('should capture exception with tags included in properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs' };\n\n analytics.setTag('testTag', 'testValue');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n testTag: 'testValue',\n ...properties,\n },\n );\n });\n\n it('should capture exception with distinct ID when set', () => {\n const error = new Error('Test error');\n const distinctId = 'user-123';\n\n analytics.setDistinctId(distinctId);\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n distinctId,\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n },\n );\n });\n\n it('should capture exception without properties when not provided', () => {\n const error = new Error('Test error');\n\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n },\n );\n });\n\n it('should merge tags with provided properties', () => {\n const error = new Error('Test error');\n const properties = { integration: 'nextjs', step: 'installation' };\n\n analytics.setTag('environment', 'test');\n analytics.setTag('version', '1.0.0');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n environment: 'test',\n version: '1.0.0',\n integration: 'nextjs',\n step: 'installation',\n },\n );\n });\n\n it('should override tags with properties when keys conflict', () => {\n const error = new Error('Test error');\n const properties = { integration: 'react' };\n\n analytics.setTag('integration', 'nextjs');\n analytics.captureException(error, properties);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n integration: 'react',\n },\n );\n });\n\n it('should always include team property in exceptions', () => {\n const error = new Error('Test error');\n\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n },\n );\n });\n });\n\n describe('integration with other methods', () => {\n it('should work correctly with setTag and captureException', () => {\n const error = new Error('Test error');\n\n analytics.setTag('integration', 'nextjs');\n analytics.setTag('forceInstall', true);\n analytics.setTag('debug', false);\n\n analytics.captureException(error, {\n arguments: JSON.stringify({ installDir: '/test' }),\n step: 'wizard-execution',\n });\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n 'test-uuid',\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n integration: 'nextjs',\n forceInstall: true,\n debug: false,\n arguments: JSON.stringify({ installDir: '/test' }),\n step: 'wizard-execution',\n },\n );\n });\n\n it('should work correctly with setDistinctId and captureException', () => {\n const error = new Error('Test error');\n const distinctId = 'user-456';\n\n analytics.setDistinctId(distinctId);\n analytics.setTag('integration', 'svelte');\n analytics.captureException(error);\n\n expect(mockPostHogInstance.captureException).toHaveBeenCalledWith(\n error,\n distinctId,\n {\n team: ANALYTICS_TEAM_TAG,\n $app_name: 'wizard',\n integration: 'svelte',\n },\n );\n });\n });\n});\n"]}
@@ -34,7 +34,7 @@ class Analytics {
34
34
  }
35
35
  captureException(error, properties = {}) {
36
36
  this.client.captureException(error, this.distinctId ?? this.anonymousId, {
37
- team: 'growth',
37
+ team: constants_1.ANALYTICS_TEAM_TAG,
38
38
  ...this.tags,
39
39
  ...properties,
40
40
  });
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n} from '../lib/constants';\nimport { v4 as uuidv4 } from 'uuid';\nimport { debug } from './debug';\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private appName = 'wizard';\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n });\n\n this.tags = { $app_name: this.appName };\n\n this.anonymousId = uuidv4();\n\n this.distinctId = undefined;\n }\n\n setDistinctId(distinctId: string) {\n this.distinctId = distinctId;\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: 'growth',\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: {\n $app_name: this.appName,\n },\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"]}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../../src/utils/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '../lib/constants';\nimport { v4 as uuidv4 } from 'uuid';\nimport { debug } from './debug';\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private appName = 'wizard';\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n });\n\n this.tags = { $app_name: this.appName };\n\n this.anonymousId = uuidv4();\n\n this.distinctId = undefined;\n }\n\n setDistinctId(distinctId: string) {\n this.distinctId = distinctId;\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: {\n $app_name: this.appName,\n },\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"]}
@@ -48,6 +48,28 @@ const constants_1 = require("../lib/constants");
48
48
  const clack_utils_1 = require("./clack-utils");
49
49
  const analytics_1 = require("./analytics");
50
50
  const urls_1 = require("./urls");
51
+ const OAUTH_CALLBACK_STYLES = `
52
+ <style>
53
+ * {
54
+ font-family: monospace;
55
+ background-color: #1b0a00;
56
+ color: #F7A502;
57
+ font-weight: medium;
58
+ font-size: 24px;
59
+ margin: .25rem;
60
+ }
61
+
62
+ .blink {
63
+ animation: blink-animation 1s steps(2, start) infinite;
64
+ }
65
+
66
+ @keyframes blink-animation {
67
+ to {
68
+ opacity: 0;
69
+ }
70
+ }
71
+ </style>
72
+ `;
51
73
  const OAuthTokenResponseSchema = zod_1.z.object({
52
74
  access_token: zod_1.z.string(),
53
75
  expires_in: zod_1.z.number(),
@@ -90,10 +112,15 @@ async function startCallbackServer(authUrl, signupUrl) {
90
112
  if (error) {
91
113
  const isAccessDenied = error === 'access_denied';
92
114
  res.writeHead(isAccessDenied ? 200 : 400, {
93
- 'Content-Type': 'text/html',
115
+ 'Content-Type': 'text/html; charset=utf-8',
94
116
  });
95
117
  res.end(`
96
118
  <html>
119
+ <head>
120
+ <meta charset="UTF-8">
121
+ <title>PostHog wizard - Authorization ${isAccessDenied ? 'cancelled' : 'failed'}</title>
122
+ ${OAUTH_CALLBACK_STYLES}
123
+ </head>
97
124
  <body>
98
125
  <p>${isAccessDenied
99
126
  ? 'Authorization cancelled.'
@@ -107,11 +134,17 @@ async function startCallbackServer(authUrl, signupUrl) {
107
134
  return;
108
135
  }
109
136
  if (code) {
110
- res.writeHead(200, { 'Content-Type': 'text/html' });
137
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
111
138
  res.end(`
112
139
  <html>
140
+ <head>
141
+ <meta charset="UTF-8">
142
+ <title>PostHog wizard is ready</title>
143
+ ${OAUTH_CALLBACK_STYLES}
144
+ </head>
113
145
  <body>
114
- <p>Authorization successful! Return to your terminal.</p>
146
+ <p>PostHog login complete!</p>
147
+ <p>Return to your terminal: the wizard is hard at work on your project<span class="blink">█</span></p>
115
148
  <script>window.close();</script>
116
149
  </body>
117
150
  </html>
@@ -119,9 +152,14 @@ async function startCallbackServer(authUrl, signupUrl) {
119
152
  callbackResolve(code);
120
153
  }
121
154
  else {
122
- res.writeHead(400, { 'Content-Type': 'text/html' });
155
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
123
156
  res.end(`
124
157
  <html>
158
+ <head>
159
+ <meta charset="UTF-8">
160
+ <title>PostHog wizard - Invalid request</title>
161
+ ${OAUTH_CALLBACK_STYLES}
162
+ </head>
125
163
  <body>
126
164
  <p>Invalid request - no authorization code received.</p>
127
165
  <p>You can close this window.</p>