@posthog/wizard 1.19.0 → 1.21.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.
Files changed (41) hide show
  1. package/dist/src/lib/agent-interface.d.ts +36 -1
  2. package/dist/src/lib/agent-interface.js +119 -4
  3. package/dist/src/lib/agent-interface.js.map +1 -1
  4. package/dist/src/lib/agent-runner.d.ts +7 -0
  5. package/dist/src/lib/agent-runner.js +201 -0
  6. package/dist/src/lib/agent-runner.js.map +1 -0
  7. package/dist/src/lib/constants.d.ts +1 -0
  8. package/dist/src/lib/constants.js +2 -1
  9. package/dist/src/lib/constants.js.map +1 -1
  10. package/dist/src/lib/framework-config.d.ts +95 -0
  11. package/dist/src/lib/framework-config.js +3 -0
  12. package/dist/src/lib/framework-config.js.map +1 -0
  13. package/dist/src/nextjs/nextjs-wizard-agent.d.ts +1 -1
  14. package/dist/src/nextjs/nextjs-wizard-agent.js +69 -133
  15. package/dist/src/nextjs/nextjs-wizard-agent.js.map +1 -1
  16. package/dist/src/steps/add-mcp-server-to-clients/MCPClient.d.ts +2 -7
  17. package/dist/src/steps/add-mcp-server-to-clients/MCPClient.js.map +1 -1
  18. package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.d.ts +33 -7
  19. package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js +2 -47
  20. package/dist/src/steps/add-mcp-server-to-clients/clients/claude-code.js.map +1 -1
  21. package/dist/src/steps/add-mcp-server-to-clients/clients/claude.d.ts +33 -6
  22. package/dist/src/steps/add-mcp-server-to-clients/clients/codex.d.ts +33 -6
  23. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.d.ts +35 -7
  24. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js +4 -1
  25. package/dist/src/steps/add-mcp-server-to-clients/clients/cursor.js.map +1 -1
  26. package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.d.ts +47 -7
  27. package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.js +25 -5
  28. package/dist/src/steps/add-mcp-server-to-clients/clients/visual-studio-code.js.map +1 -1
  29. package/dist/src/steps/add-mcp-server-to-clients/clients/zed.d.ts +47 -16
  30. package/dist/src/steps/add-mcp-server-to-clients/clients/zed.js +22 -11
  31. package/dist/src/steps/add-mcp-server-to-clients/clients/zed.js.map +1 -1
  32. package/dist/src/steps/add-mcp-server-to-clients/defaults.d.ts +40 -6
  33. package/dist/src/steps/add-mcp-server-to-clients/defaults.js +29 -8
  34. package/dist/src/steps/add-mcp-server-to-clients/defaults.js.map +1 -1
  35. package/dist/src/utils/__tests__/analytics.test.js +11 -10
  36. package/dist/src/utils/__tests__/analytics.test.js.map +1 -1
  37. package/dist/src/utils/analytics.js +1 -1
  38. package/dist/src/utils/analytics.js.map +1 -1
  39. package/dist/src/utils/oauth.js +42 -4
  40. package/dist/src/utils/oauth.js.map +1 -1
  41. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import z from 'zod';
2
2
  export declare const DefaultMCPClientConfig: z.ZodObject<{
3
- mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
3
+ mcpServers: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
4
4
  command: z.ZodOptional<z.ZodString>;
5
5
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
6
6
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -12,9 +12,18 @@ export declare const DefaultMCPClientConfig: z.ZodObject<{
12
12
  command?: string | undefined;
13
13
  args?: string[] | undefined;
14
14
  env?: Record<string, string> | undefined;
15
- }>>;
15
+ }>, z.ZodObject<{
16
+ url: z.ZodString;
17
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
18
+ }, "strip", z.ZodTypeAny, {
19
+ url: string;
20
+ headers?: Record<string, string> | undefined;
21
+ }, {
22
+ url: string;
23
+ headers?: Record<string, string> | undefined;
24
+ }>]>>;
16
25
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
17
- mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
26
+ mcpServers: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
18
27
  command: z.ZodOptional<z.ZodString>;
19
28
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
20
29
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -26,9 +35,18 @@ export declare const DefaultMCPClientConfig: z.ZodObject<{
26
35
  command?: string | undefined;
27
36
  args?: string[] | undefined;
28
37
  env?: Record<string, string> | undefined;
29
- }>>;
38
+ }>, z.ZodObject<{
39
+ url: z.ZodString;
40
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
41
+ }, "strip", z.ZodTypeAny, {
42
+ url: string;
43
+ headers?: Record<string, string> | undefined;
44
+ }, {
45
+ url: string;
46
+ headers?: Record<string, string> | undefined;
47
+ }>]>>;
30
48
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
31
- mcpServers: z.ZodRecord<z.ZodString, z.ZodObject<{
49
+ mcpServers: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
32
50
  command: z.ZodOptional<z.ZodString>;
33
51
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
34
52
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -40,7 +58,16 @@ export declare const DefaultMCPClientConfig: z.ZodObject<{
40
58
  command?: string | undefined;
41
59
  args?: string[] | undefined;
42
60
  env?: Record<string, string> | undefined;
43
- }>>;
61
+ }>, z.ZodObject<{
62
+ url: z.ZodString;
63
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
64
+ }, "strip", z.ZodTypeAny, {
65
+ url: string;
66
+ headers?: Record<string, string> | undefined;
67
+ }, {
68
+ url: string;
69
+ headers?: Record<string, string> | undefined;
70
+ }>]>>;
44
71
  }, z.ZodTypeAny, "passthrough">>;
45
72
  export declare const AVAILABLE_FEATURES: {
46
73
  'Data & Analytics': {
@@ -61,6 +88,13 @@ export declare const AVAILABLE_FEATURES: {
61
88
  };
62
89
  export declare const ALL_FEATURE_VALUES: string[];
63
90
  type MCPServerType = 'sse' | 'streamable-http';
91
+ export declare const buildMCPUrl: (type: MCPServerType, selectedFeatures?: string[], local?: boolean) => string;
92
+ export declare const getNativeHTTPServerConfig: (apiKey: string, type: MCPServerType, selectedFeatures?: string[], local?: boolean) => {
93
+ url: string;
94
+ headers: {
95
+ Authorization: string;
96
+ };
97
+ };
64
98
  export declare const getDefaultServerConfig: (apiKey: string, type: MCPServerType, selectedFeatures?: string[], local?: boolean) => {
65
99
  command: string;
66
100
  args: string[];
@@ -3,15 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getDefaultServerConfig = exports.ALL_FEATURE_VALUES = exports.AVAILABLE_FEATURES = exports.DefaultMCPClientConfig = void 0;
6
+ exports.getDefaultServerConfig = exports.getNativeHTTPServerConfig = exports.buildMCPUrl = exports.ALL_FEATURE_VALUES = exports.AVAILABLE_FEATURES = exports.DefaultMCPClientConfig = void 0;
7
7
  const zod_1 = __importDefault(require("zod"));
8
8
  exports.DefaultMCPClientConfig = zod_1.default
9
9
  .object({
10
- mcpServers: zod_1.default.record(zod_1.default.string(), zod_1.default.object({
11
- command: zod_1.default.string().optional(),
12
- args: zod_1.default.array(zod_1.default.string()).optional(),
13
- env: zod_1.default.record(zod_1.default.string(), zod_1.default.string()).optional(),
14
- })),
10
+ mcpServers: zod_1.default.record(zod_1.default.string(), zod_1.default.union([
11
+ zod_1.default.object({
12
+ command: zod_1.default.string().optional(),
13
+ args: zod_1.default.array(zod_1.default.string()).optional(),
14
+ env: zod_1.default.record(zod_1.default.string(), zod_1.default.string()).optional(),
15
+ }),
16
+ zod_1.default.object({
17
+ url: zod_1.default.string(),
18
+ headers: zod_1.default.record(zod_1.default.string(), zod_1.default.string()).optional(),
19
+ }),
20
+ ])),
15
21
  })
16
22
  .passthrough();
17
23
  exports.AVAILABLE_FEATURES = {
@@ -61,15 +67,30 @@ exports.AVAILABLE_FEATURES = {
61
67
  exports.ALL_FEATURE_VALUES = Object.values(exports.AVAILABLE_FEATURES)
62
68
  .flat()
63
69
  .map((feature) => feature.value);
64
- const getDefaultServerConfig = (apiKey, type, selectedFeatures, local) => {
70
+ const buildMCPUrl = (type, selectedFeatures, local) => {
65
71
  const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';
66
72
  const baseUrl = `${host}/${type === 'sse' ? 'sse' : 'mcp'}`;
67
73
  const isAllFeaturesSelected = selectedFeatures &&
68
74
  selectedFeatures.length === exports.ALL_FEATURE_VALUES.length &&
69
75
  exports.ALL_FEATURE_VALUES.every((feature) => selectedFeatures.includes(feature));
70
- const urlWithFeatures = selectedFeatures && selectedFeatures.length > 0 && !isAllFeaturesSelected
76
+ return selectedFeatures &&
77
+ selectedFeatures.length > 0 &&
78
+ !isAllFeaturesSelected
71
79
  ? `${baseUrl}?features=${selectedFeatures.join(',')}`
72
80
  : baseUrl;
81
+ };
82
+ exports.buildMCPUrl = buildMCPUrl;
83
+ const getNativeHTTPServerConfig = (apiKey, type, selectedFeatures, local) => {
84
+ return {
85
+ url: (0, exports.buildMCPUrl)(type, selectedFeatures, local),
86
+ headers: {
87
+ Authorization: `Bearer ${apiKey}`,
88
+ },
89
+ };
90
+ };
91
+ exports.getNativeHTTPServerConfig = getNativeHTTPServerConfig;
92
+ const getDefaultServerConfig = (apiKey, type, selectedFeatures, local) => {
93
+ const urlWithFeatures = (0, exports.buildMCPUrl)(type, selectedFeatures, local);
73
94
  return {
74
95
  command: 'npx',
75
96
  args: [
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/defaults.ts"],"names":[],"mappings":"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","sourcesContent":["import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n ),\n })\n .passthrough();\n\nexport const AVAILABLE_FEATURES = {\n 'Data & Analytics': [\n {\n value: 'dashboards',\n label: 'Dashboards',\n hint: 'Dashboard creation and management',\n },\n {\n value: 'insights',\n label: 'Insights',\n hint: 'Analytics insights and SQL queries',\n },\n {\n value: 'experiments',\n label: 'Experiments',\n hint: 'A/B testing experiments',\n },\n {\n value: 'llm-analytics',\n label: 'LLM Analytics',\n hint: 'LLM usage and cost tracking',\n },\n ],\n 'Development Tools': [\n {\n value: 'error-tracking',\n label: 'Error Tracking',\n hint: 'Error monitoring and debugging',\n },\n { value: 'flags', label: 'Feature Flags', hint: 'Feature flag management' },\n ],\n 'Platform & Management': [\n {\n value: 'workspace',\n label: 'Workspace',\n hint: 'Organization and project management',\n },\n {\n value: 'docs',\n label: 'Documentation',\n hint: 'PostHog documentation search',\n },\n ],\n};\n\nexport const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)\n .flat()\n .map((feature) => feature.value);\n\ntype MCPServerType = 'sse' | 'streamable-http';\n\nexport const getDefaultServerConfig = (\n apiKey: string,\n type: MCPServerType,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';\n const baseUrl = `${host}/${type === 'sse' ? 'sse' : 'mcp'}`;\n\n const isAllFeaturesSelected =\n selectedFeatures &&\n selectedFeatures.length === ALL_FEATURE_VALUES.length &&\n ALL_FEATURE_VALUES.every((feature) => selectedFeatures.includes(feature));\n\n const urlWithFeatures =\n selectedFeatures && selectedFeatures.length > 0 && !isAllFeaturesSelected\n ? `${baseUrl}?features=${selectedFeatures.join(',')}`\n : baseUrl;\n\n return {\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n urlWithFeatures,\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n };\n};\n"]}
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../../src/steps/add-mcp-server-to-clients/defaults.ts"],"names":[],"mappings":"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","sourcesContent":["import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.union([\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n z.object({\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ]),\n ),\n })\n .passthrough();\n\nexport const AVAILABLE_FEATURES = {\n 'Data & Analytics': [\n {\n value: 'dashboards',\n label: 'Dashboards',\n hint: 'Dashboard creation and management',\n },\n {\n value: 'insights',\n label: 'Insights',\n hint: 'Analytics insights and SQL queries',\n },\n {\n value: 'experiments',\n label: 'Experiments',\n hint: 'A/B testing experiments',\n },\n {\n value: 'llm-analytics',\n label: 'LLM Analytics',\n hint: 'LLM usage and cost tracking',\n },\n ],\n 'Development Tools': [\n {\n value: 'error-tracking',\n label: 'Error Tracking',\n hint: 'Error monitoring and debugging',\n },\n { value: 'flags', label: 'Feature Flags', hint: 'Feature flag management' },\n ],\n 'Platform & Management': [\n {\n value: 'workspace',\n label: 'Workspace',\n hint: 'Organization and project management',\n },\n {\n value: 'docs',\n label: 'Documentation',\n hint: 'PostHog documentation search',\n },\n ],\n};\n\nexport const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)\n .flat()\n .map((feature) => feature.value);\n\ntype MCPServerType = 'sse' | 'streamable-http';\n\nexport const buildMCPUrl = (\n type: MCPServerType,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';\n const baseUrl = `${host}/${type === 'sse' ? 'sse' : 'mcp'}`;\n\n const isAllFeaturesSelected =\n selectedFeatures &&\n selectedFeatures.length === ALL_FEATURE_VALUES.length &&\n ALL_FEATURE_VALUES.every((feature) => selectedFeatures.includes(feature));\n\n return selectedFeatures &&\n selectedFeatures.length > 0 &&\n !isAllFeaturesSelected\n ? `${baseUrl}?features=${selectedFeatures.join(',')}`\n : baseUrl;\n};\n\nexport const getNativeHTTPServerConfig = (\n apiKey: string,\n type: MCPServerType,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n return {\n url: buildMCPUrl(type, selectedFeatures, local),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n },\n };\n};\n\nexport const getDefaultServerConfig = (\n apiKey: string,\n type: MCPServerType,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const urlWithFeatures = buildMCPUrl(type, selectedFeatures, local);\n\n return {\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n urlWithFeatures,\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n };\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>
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/utils/oauth.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from 'node:crypto';\nimport * as http from 'node:http';\nimport axios from 'axios';\nimport chalk from 'chalk';\nimport opn from 'opn';\nimport { z } from 'zod';\nimport clack from './clack';\nimport { ISSUES_URL, OAUTH_PORT } from '../lib/constants';\nimport { abort } from './clack-utils';\nimport { analytics } from './analytics';\nimport type { CloudRegion } from './types';\nimport { getCloudUrlFromRegion, getOauthClientIdFromRegion } from './urls';\n\nconst OAuthTokenResponseSchema = z.object({\n access_token: z.string(),\n expires_in: z.number(),\n token_type: z.string(),\n scope: z.string(),\n refresh_token: z.string(),\n scoped_teams: z.array(z.number()).optional(),\n scoped_organizations: z.array(z.string()).optional(),\n});\n\nexport type OAuthTokenResponse = z.infer<typeof OAuthTokenResponseSchema>;\n\ninterface OAuthConfig {\n scopes: string[];\n cloudRegion: CloudRegion;\n signup?: boolean;\n}\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\nasync function startCallbackServer(\n authUrl: string,\n signupUrl: string,\n): Promise<{\n server: http.Server;\n waitForCallback: () => Promise<string>;\n}> {\n return new Promise((resolve, reject) => {\n let callbackResolve: (code: string) => void;\n let callbackReject: (error: Error) => void;\n\n const waitForCallback = () =>\n new Promise<string>((res, rej) => {\n callbackResolve = res;\n callbackReject = rej;\n });\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end();\n return;\n }\n const url = new URL(req.url, `http://localhost:${OAUTH_PORT}`);\n\n if (url.pathname === '/authorize') {\n const isSignup = url.searchParams.get('signup') === 'true';\n const redirectUrl = isSignup ? signupUrl : authUrl;\n res.writeHead(302, { Location: redirectUrl });\n res.end();\n return;\n }\n\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n const isAccessDenied = error === 'access_denied';\n res.writeHead(isAccessDenied ? 200 : 400, {\n 'Content-Type': 'text/html',\n });\n res.end(`\n <html>\n <body>\n <p>${\n isAccessDenied\n ? 'Authorization cancelled.'\n : `Authorization failed.`\n }</p>\n <p>Return to your terminal. This window will close automatically.</p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackReject(new Error(`OAuth error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <p>Authorization successful! Return to your terminal.</p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackResolve(code);\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(`\n <html>\n <body>\n <p>Invalid request - no authorization code received.</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `);\n }\n });\n\n server.listen(OAUTH_PORT, () => {\n resolve({ server, waitForCallback });\n });\n\n server.on('error', reject);\n });\n}\n\nasync function exchangeCodeForToken(\n code: string,\n codeVerifier: string,\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const cloudUrl = getCloudUrlFromRegion(config.cloudRegion);\n\n const response = await axios.post(\n `${cloudUrl}/oauth/token`,\n {\n grant_type: 'authorization_code',\n code,\n redirect_uri: `http://localhost:${OAUTH_PORT}/callback`,\n client_id: getOauthClientIdFromRegion(config.cloudRegion),\n code_verifier: codeVerifier,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n return OAuthTokenResponseSchema.parse(response.data);\n}\n\nexport async function performOAuthFlow(\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const cloudUrl = getCloudUrlFromRegion(config.cloudRegion);\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n\n const authUrl = new URL(`${cloudUrl}/oauth/authorize`);\n authUrl.searchParams.set(\n 'client_id',\n getOauthClientIdFromRegion(config.cloudRegion),\n );\n authUrl.searchParams.set(\n 'redirect_uri',\n `http://localhost:${OAUTH_PORT}/callback`,\n );\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('scope', config.scopes.join(' '));\n authUrl.searchParams.set('required_access_level', 'project');\n\n const signupUrl = new URL(\n `${cloudUrl}/signup?next=${encodeURIComponent(authUrl.toString())}`,\n );\n\n const localSignupUrl = `http://localhost:${OAUTH_PORT}/authorize?signup=true`;\n const localLoginUrl = `http://localhost:${OAUTH_PORT}/authorize`;\n\n const urlToOpen = config.signup ? localSignupUrl : localLoginUrl;\n\n const { server, waitForCallback } = await startCallbackServer(\n authUrl.toString(),\n signupUrl.toString(),\n );\n\n clack.log.info(\n `${chalk.bold(\n \"If the browser window didn't open automatically, please open the following link to be redirected to PostHog:\",\n )}\\n\\n${chalk.cyan(urlToOpen)}${\n config.signup\n ? `\\n\\nIf you already have an account, you can use this link:\\n\\n${chalk.cyan(\n localLoginUrl,\n )}`\n : ``\n }`,\n );\n\n if (process.env.NODE_ENV !== 'test') {\n opn(urlToOpen, { wait: false }).catch(() => {\n // opn throws in environments without a browser\n });\n }\n\n const loginSpinner = clack.spinner();\n loginSpinner.start('Waiting for authorization...');\n\n try {\n const code = await Promise.race([\n waitForCallback(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Authorization timed out')), 60_000),\n ),\n ]);\n\n const token = await exchangeCodeForToken(code, codeVerifier, config);\n\n server.close();\n loginSpinner.stop('Authorization complete!');\n\n return token;\n } catch (e) {\n loginSpinner.stop('Authorization failed.');\n server.close();\n\n const error = e instanceof Error ? e : new Error('Unknown error');\n\n if (error.message.includes('timeout')) {\n clack.log.error('Authorization timed out. Please try again.');\n } else if (error.message.includes('access_denied')) {\n clack.log.info(\n `${chalk.yellow(\n 'Authorization was cancelled.',\n )}\\n\\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\\n\\n${chalk.dim(\n 'You can try again by re-running the wizard.',\n )}`,\n );\n } else {\n clack.log.error(\n `${chalk.red('Authorization failed:')}\\n\\n${\n error.message\n }\\n\\n${chalk.dim(\n `If you think this is a bug in the PostHog wizard, please create an issue:\\n${ISSUES_URL}`,\n )}`,\n );\n }\n\n analytics.captureException(error, {\n step: 'oauth_flow',\n cloud_region: config.cloudRegion,\n });\n\n await abort();\n throw error;\n }\n}\n"]}
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/utils/oauth.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoMA,4CAyGC;AA7SD,oDAAsC;AACtC,gDAAkC;AAClC,kDAA0B;AAC1B,kDAA0B;AAC1B,8CAAsB;AACtB,6BAAwB;AACxB,oDAA4B;AAC5B,gDAA0D;AAC1D,+CAAsC;AACtC,2CAAwC;AAExC,iCAA2E;AAE3E,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;CAqB7B,CAAC;AAEF,MAAM,wBAAwB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;IACxB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;IACtB,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,aAAa,EAAE,OAAC,CAAC,MAAM,EAAE;IACzB,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC5C,oBAAoB,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAUH,SAAS,oBAAoB;IAC3B,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,OAAe,EACf,SAAiB;IAKjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,eAAuC,CAAC;QAC5C,IAAI,cAAsC,CAAC;QAE3C,MAAM,eAAe,GAAG,GAAG,EAAE,CAC3B,IAAI,OAAO,CAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC/B,eAAe,GAAG,GAAG,CAAC;YACtB,cAAc,GAAG,GAAG,CAAC;QACvB,CAAC,CAAC,CAAC;QAEL,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,sBAAU,EAAE,CAAC,CAAC;YAE/D,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;gBAClC,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC;gBAC3D,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;gBACnD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC9C,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAE5C,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,cAAc,GAAG,KAAK,KAAK,eAAe,CAAC;gBACjD,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;oBACxC,cAAc,EAAE,0BAA0B;iBAC3C,CAAC,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC;;;;sDAKA,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QACjC;gBACE,qBAAqB;;;mBAIrB,cAAc;oBACZ,CAAC,CAAC,0BAA0B;oBAC5B,CAAC,CAAC,uBACN;;;;;SAKL,CAAC,CAAC;gBACH,cAAc,CAAC,IAAI,KAAK,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACT,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC;;;;;gBAKA,qBAAqB;;;;;;;;SAQ5B,CAAC,CAAC;gBACH,eAAe,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC;;;;;gBAKA,qBAAqB;;;;;;;SAO5B,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,sBAAU,EAAE,GAAG,EAAE;YAC7B,OAAO,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,IAAY,EACZ,YAAoB,EACpB,MAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAA,4BAAqB,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAE3D,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAC/B,GAAG,QAAQ,cAAc,EACzB;QACE,UAAU,EAAE,oBAAoB;QAChC,IAAI;QACJ,YAAY,EAAE,oBAAoB,sBAAU,WAAW;QACvD,SAAS,EAAE,IAAA,iCAA0B,EAAC,MAAM,CAAC,WAAW,CAAC;QACzD,aAAa,EAAE,YAAY;KAC5B,EACD;QACE,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;SACnC;KACF,CACF,CAAC;IAEF,OAAO,wBAAwB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC;AAEM,KAAK,UAAU,gBAAgB,CACpC,MAAmB;IAEnB,MAAM,QAAQ,GAAG,IAAA,4BAAqB,EAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,oBAAoB,EAAE,CAAC;IAC5C,MAAM,aAAa,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,QAAQ,kBAAkB,CAAC,CAAC;IACvD,OAAO,CAAC,YAAY,CAAC,GAAG,CACtB,WAAW,EACX,IAAA,iCAA0B,EAAC,MAAM,CAAC,WAAW,CAAC,CAC/C,CAAC;IACF,OAAO,CAAC,YAAY,CAAC,GAAG,CACtB,cAAc,EACd,oBAAoB,sBAAU,WAAW,CAC1C,CAAC;IACF,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAClD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IAC1D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;IAC1D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,SAAS,CAAC,CAAC;IAE7D,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,GAAG,QAAQ,gBAAgB,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CACpE,CAAC;IAEF,MAAM,cAAc,GAAG,oBAAoB,sBAAU,wBAAwB,CAAC;IAC9E,MAAM,aAAa,GAAG,oBAAoB,sBAAU,YAAY,CAAC;IAEjE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC;IAEjE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,mBAAmB,CAC3D,OAAO,CAAC,QAAQ,EAAE,EAClB,SAAS,CAAC,QAAQ,EAAE,CACrB,CAAC;IAEF,eAAK,CAAC,GAAG,CAAC,IAAI,CACZ,GAAG,eAAK,CAAC,IAAI,CACX,8GAA8G,CAC/G,OAAO,eAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAC3B,MAAM,CAAC,MAAM;QACX,CAAC,CAAC,iEAAiE,eAAK,CAAC,IAAI,CACzE,aAAa,CACd,EAAE;QACL,CAAC,CAAC,EACN,EAAE,CACH,CAAC;IAEF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,IAAA,aAAG,EAAC,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACzC,+CAA+C;QACjD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,YAAY,GAAG,eAAK,CAAC,OAAO,EAAE,CAAC;IACrC,YAAY,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YAC9B,eAAe,EAAE;YACjB,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,MAAM,CAAC,CACvE;SACF,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;QAErE,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAE7C,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,YAAY,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QAElE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,eAAK,CAAC,GAAG,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACnD,eAAK,CAAC,GAAG,CAAC,IAAI,CACZ,GAAG,eAAK,CAAC,MAAM,CACb,8BAA8B,CAC/B,iHAAiH,eAAK,CAAC,GAAG,CACzH,6CAA6C,CAC9C,EAAE,CACJ,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,eAAK,CAAC,GAAG,CAAC,KAAK,CACb,GAAG,eAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,OACnC,KAAK,CAAC,OACR,OAAO,eAAK,CAAC,GAAG,CACd,8EAA8E,sBAAU,EAAE,CAC3F,EAAE,CACJ,CAAC;QACJ,CAAC;QAED,qBAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE;YAChC,IAAI,EAAE,YAAY;YAClB,YAAY,EAAE,MAAM,CAAC,WAAW;SACjC,CAAC,CAAC;QAEH,MAAM,IAAA,mBAAK,GAAE,CAAC;QACd,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["import * as crypto from 'node:crypto';\nimport * as http from 'node:http';\nimport axios from 'axios';\nimport chalk from 'chalk';\nimport opn from 'opn';\nimport { z } from 'zod';\nimport clack from './clack';\nimport { ISSUES_URL, OAUTH_PORT } from '../lib/constants';\nimport { abort } from './clack-utils';\nimport { analytics } from './analytics';\nimport type { CloudRegion } from './types';\nimport { getCloudUrlFromRegion, getOauthClientIdFromRegion } from './urls';\n\nconst OAUTH_CALLBACK_STYLES = `\n <style>\n * {\n font-family: monospace;\n background-color: #1b0a00;\n color: #F7A502;\n font-weight: medium;\n font-size: 24px;\n margin: .25rem;\n }\n\n .blink {\n animation: blink-animation 1s steps(2, start) infinite;\n }\n\n @keyframes blink-animation {\n to {\n opacity: 0;\n }\n }\n </style>\n`;\n\nconst OAuthTokenResponseSchema = z.object({\n access_token: z.string(),\n expires_in: z.number(),\n token_type: z.string(),\n scope: z.string(),\n refresh_token: z.string(),\n scoped_teams: z.array(z.number()).optional(),\n scoped_organizations: z.array(z.string()).optional(),\n});\n\nexport type OAuthTokenResponse = z.infer<typeof OAuthTokenResponseSchema>;\n\ninterface OAuthConfig {\n scopes: string[];\n cloudRegion: CloudRegion;\n signup?: boolean;\n}\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\nasync function startCallbackServer(\n authUrl: string,\n signupUrl: string,\n): Promise<{\n server: http.Server;\n waitForCallback: () => Promise<string>;\n}> {\n return new Promise((resolve, reject) => {\n let callbackResolve: (code: string) => void;\n let callbackReject: (error: Error) => void;\n\n const waitForCallback = () =>\n new Promise<string>((res, rej) => {\n callbackResolve = res;\n callbackReject = rej;\n });\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end();\n return;\n }\n const url = new URL(req.url, `http://localhost:${OAUTH_PORT}`);\n\n if (url.pathname === '/authorize') {\n const isSignup = url.searchParams.get('signup') === 'true';\n const redirectUrl = isSignup ? signupUrl : authUrl;\n res.writeHead(302, { Location: redirectUrl });\n res.end();\n return;\n }\n\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n const isAccessDenied = error === 'access_denied';\n res.writeHead(isAccessDenied ? 200 : 400, {\n 'Content-Type': 'text/html; charset=utf-8',\n });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Authorization ${\n isAccessDenied ? 'cancelled' : 'failed'\n }</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>${\n isAccessDenied\n ? 'Authorization cancelled.'\n : `Authorization failed.`\n }</p>\n <p>Return to your terminal. This window will close automatically.</p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackReject(new Error(`OAuth error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard is ready</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>PostHog login complete!</p>\n <p>Return to your terminal: the wizard is hard at work on your project<span class=\"blink\">█</span></p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackResolve(code);\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Invalid request</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>Invalid request - no authorization code received.</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `);\n }\n });\n\n server.listen(OAUTH_PORT, () => {\n resolve({ server, waitForCallback });\n });\n\n server.on('error', reject);\n });\n}\n\nasync function exchangeCodeForToken(\n code: string,\n codeVerifier: string,\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const cloudUrl = getCloudUrlFromRegion(config.cloudRegion);\n\n const response = await axios.post(\n `${cloudUrl}/oauth/token`,\n {\n grant_type: 'authorization_code',\n code,\n redirect_uri: `http://localhost:${OAUTH_PORT}/callback`,\n client_id: getOauthClientIdFromRegion(config.cloudRegion),\n code_verifier: codeVerifier,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n return OAuthTokenResponseSchema.parse(response.data);\n}\n\nexport async function performOAuthFlow(\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const cloudUrl = getCloudUrlFromRegion(config.cloudRegion);\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n\n const authUrl = new URL(`${cloudUrl}/oauth/authorize`);\n authUrl.searchParams.set(\n 'client_id',\n getOauthClientIdFromRegion(config.cloudRegion),\n );\n authUrl.searchParams.set(\n 'redirect_uri',\n `http://localhost:${OAUTH_PORT}/callback`,\n );\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('scope', config.scopes.join(' '));\n authUrl.searchParams.set('required_access_level', 'project');\n\n const signupUrl = new URL(\n `${cloudUrl}/signup?next=${encodeURIComponent(authUrl.toString())}`,\n );\n\n const localSignupUrl = `http://localhost:${OAUTH_PORT}/authorize?signup=true`;\n const localLoginUrl = `http://localhost:${OAUTH_PORT}/authorize`;\n\n const urlToOpen = config.signup ? localSignupUrl : localLoginUrl;\n\n const { server, waitForCallback } = await startCallbackServer(\n authUrl.toString(),\n signupUrl.toString(),\n );\n\n clack.log.info(\n `${chalk.bold(\n \"If the browser window didn't open automatically, please open the following link to be redirected to PostHog:\",\n )}\\n\\n${chalk.cyan(urlToOpen)}${\n config.signup\n ? `\\n\\nIf you already have an account, you can use this link:\\n\\n${chalk.cyan(\n localLoginUrl,\n )}`\n : ``\n }`,\n );\n\n if (process.env.NODE_ENV !== 'test') {\n opn(urlToOpen, { wait: false }).catch(() => {\n // opn throws in environments without a browser\n });\n }\n\n const loginSpinner = clack.spinner();\n loginSpinner.start('Waiting for authorization...');\n\n try {\n const code = await Promise.race([\n waitForCallback(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Authorization timed out')), 60_000),\n ),\n ]);\n\n const token = await exchangeCodeForToken(code, codeVerifier, config);\n\n server.close();\n loginSpinner.stop('Authorization complete!');\n\n return token;\n } catch (e) {\n loginSpinner.stop('Authorization failed.');\n server.close();\n\n const error = e instanceof Error ? e : new Error('Unknown error');\n\n if (error.message.includes('timeout')) {\n clack.log.error('Authorization timed out. Please try again.');\n } else if (error.message.includes('access_denied')) {\n clack.log.info(\n `${chalk.yellow(\n 'Authorization was cancelled.',\n )}\\n\\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\\n\\n${chalk.dim(\n 'You can try again by re-running the wizard.',\n )}`,\n );\n } else {\n clack.log.error(\n `${chalk.red('Authorization failed:')}\\n\\n${\n error.message\n }\\n\\n${chalk.dim(\n `If you think this is a bug in the PostHog wizard, please create an issue:\\n${ISSUES_URL}`,\n )}`,\n );\n }\n\n analytics.captureException(error, {\n step: 'oauth_flow',\n cloud_region: config.cloudRegion,\n });\n\n await abort();\n throw error;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/wizard",
3
- "version": "1.19.0",
3
+ "version": "1.21.0",
4
4
  "homepage": "https://github.com/PostHog/wizard",
5
5
  "repository": "https://github.com/PostHog/wizard",
6
6
  "description": "The PostHog wizard helps you to configure your project",
@@ -35,7 +35,7 @@
35
35
  "@clack/core": "^0.3.4",
36
36
  "@clack/prompts": "0.7.0",
37
37
  "@langchain/core": "^0.3.40",
38
- "@posthog/agent": "1.11.0",
38
+ "@posthog/agent": "1.24.2",
39
39
  "axios": "1.7.4",
40
40
  "chalk": "^2.4.1",
41
41
  "fast-glob": "^3.3.3",