@posthog/wizard 0.2.3 → 0.2.5

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 (38) hide show
  1. package/README.md +10 -5
  2. package/dist/src/lib/constants.d.ts +2 -1
  3. package/dist/src/lib/constants.js +3 -6
  4. package/dist/src/lib/constants.js.map +1 -1
  5. package/dist/src/nextjs/docs.js +33 -25
  6. package/dist/src/nextjs/docs.js.map +1 -1
  7. package/dist/src/nextjs/nextjs-wizard.d.ts +4 -4
  8. package/dist/src/nextjs/nextjs-wizard.js +71 -34
  9. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  10. package/dist/src/nextjs/prompts.d.ts +1 -1
  11. package/dist/src/nextjs/prompts.js +9 -3
  12. package/dist/src/nextjs/prompts.js.map +1 -1
  13. package/dist/src/nextjs/utils.d.ts +3 -1
  14. package/dist/src/nextjs/utils.js +30 -7
  15. package/dist/src/nextjs/utils.js.map +1 -1
  16. package/dist/src/run.d.ts +1 -0
  17. package/dist/src/run.js +14 -10
  18. package/dist/src/run.js.map +1 -1
  19. package/dist/src/telemetry.js +1 -1
  20. package/dist/src/telemetry.js.map +1 -1
  21. package/dist/src/utils/analytics.d.ts +9 -1
  22. package/dist/src/utils/analytics.js +52 -3
  23. package/dist/src/utils/analytics.js.map +1 -1
  24. package/dist/src/utils/clack-utils.d.ts +14 -11
  25. package/dist/src/utils/clack-utils.js +41 -36
  26. package/dist/src/utils/clack-utils.js.map +1 -1
  27. package/dist/src/utils/clack.js.map +1 -1
  28. package/dist/src/utils/debug.js.map +1 -1
  29. package/dist/src/utils/environment.js.map +1 -1
  30. package/dist/src/utils/file-utils.js +7 -7
  31. package/dist/src/utils/file-utils.js.map +1 -1
  32. package/dist/src/utils/package-manager.d.ts +4 -3
  33. package/dist/src/utils/package-manager.js +26 -27
  34. package/dist/src/utils/package-manager.js.map +1 -1
  35. package/dist/src/utils/query.js.map +1 -1
  36. package/dist/src/utils/types.d.ts +4 -4
  37. package/dist/src/utils/types.js.map +1 -1
  38. package/package.json +3 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
-
2
1
  <p align="center">
3
2
  <img alt="posthoglogo" src="https://user-images.githubusercontent.com/65415371/205059737-c8a4f836-4889-4654-902e-f302b187b6a0.png">
4
3
  </p>
5
4
 
6
- > **⚠️ Experimental:** This wizard is still in an experimental phase.
7
- > If you have any feedback, please drop an email to **joshua** [at] **posthog** [dot] **com**.
5
+ > **⚠️ Experimental:** This wizard is still in an experimental phase. If you
6
+ > have any feedback, please drop an email to **joshua** [at] **posthog** [dot]
7
+ > **com**.
8
8
 
9
9
  <h1>PostHog Wizard</h1>
10
10
  <h4>The PostHog Wizard helps you quickly add PostHog to your project.</h4>
@@ -17,7 +17,9 @@ To use the wizard, you can run it directly using:
17
17
  npx @posthog/wizard
18
18
  ```
19
19
 
20
- Currently the wizard can be used for Next.js only. If you have other platforms you would like the wizard to support, please open a [GitHub issue](https://github.com/posthog/wizard/issues)!
20
+ Currently the wizard can be used for Next.js only. If you have other platforms
21
+ you would like the wizard to support, please open a
22
+ [GitHub issue](https://github.com/posthog/wizard/issues)!
21
23
 
22
24
  # Options
23
25
 
@@ -30,5 +32,8 @@ The following CLI arguments are available:
30
32
  | `--debug` | Enable verbose logging | boolean | `false` | | `POSTHOG_WIZARD_DEBUG` |
31
33
  | `--integration` | Choose the integration to setup | choices | Select integration during setup | "nextjs" | `POSTHOG_WIZARD_INTEGRATION` |
32
34
  | `--force-install` | Force install the SDK NPM package (use with caution!) | boolean | `false` | | |
35
+ | `--install-dir` | Relative path to install in | string | `.` | | `POSTHOG_WIZARD_INSTALL_DIR` |
33
36
 
34
- > Note: A large amount of the scaffolding for this came from the amazing Sentry wizard, which you can find [here](https://github.com/getsentry/sentry-wizard) 💖
37
+ > Note: A large amount of the scaffolding for this came from the amazing Sentry
38
+ > wizard, which you can find [here](https://github.com/getsentry/sentry-wizard)
39
+ > 💖
@@ -13,8 +13,9 @@ export interface Args {
13
13
  }
14
14
  export declare const DEFAULT_URL = "http://us.posthog.com";
15
15
  export declare const ISSUES_URL = "https://github.com/posthog/wizard/issues";
16
- export declare const INSTALL_DIR: string;
17
16
  export declare const CLOUD_URL = "https://us.posthog.com";
18
17
  export declare const DEFAULT_HOST_URL = "https://us.i.posthog.com";
18
+ export declare const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = "sTMFPsFhdP1Ssg";
19
+ export declare const ANALYTICS_HOST_URL = "https://internal-t.posthog.com";
19
20
  export declare const DUMMY_PROJECT_API_KEY = "_YOUR_POSTHOG_PROJECT_API_KEY_";
20
21
  export {};
@@ -1,12 +1,8 @@
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
- exports.DUMMY_PROJECT_API_KEY = exports.DEFAULT_HOST_URL = exports.CLOUD_URL = exports.INSTALL_DIR = exports.ISSUES_URL = exports.DEFAULT_URL = exports.Integration = void 0;
3
+ exports.DUMMY_PROJECT_API_KEY = exports.ANALYTICS_HOST_URL = exports.ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = exports.DEFAULT_HOST_URL = exports.CLOUD_URL = exports.ISSUES_URL = exports.DEFAULT_URL = exports.Integration = void 0;
7
4
  exports.getIntegrationDescription = getIntegrationDescription;
8
5
  exports.getIntegrationChoices = getIntegrationChoices;
9
- const path_1 = __importDefault(require("path"));
10
6
  var Integration;
11
7
  (function (Integration) {
12
8
  Integration["nextjs"] = "nextjs";
@@ -27,8 +23,9 @@ function getIntegrationChoices() {
27
23
  }
28
24
  exports.DEFAULT_URL = 'http://us.posthog.com';
29
25
  exports.ISSUES_URL = 'https://github.com/posthog/wizard/issues';
30
- exports.INSTALL_DIR = path_1.default.join(process.cwd(), process.env.POSTHOG_WIZARD_INSTALL_DIR ?? '');
31
26
  exports.CLOUD_URL = 'https://us.posthog.com';
32
27
  exports.DEFAULT_HOST_URL = 'https://us.i.posthog.com';
28
+ exports.ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';
29
+ exports.ANALYTICS_HOST_URL = 'https://internal-t.posthog.com';
33
30
  exports.DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_API_KEY_';
34
31
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":";;;;;;AAMA,8DAOC;AAOD,sDAKC;AAzBD,gDAAwB;AAExB,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,gCAAiB,CAAA;AACnB,CAAC,EAFW,WAAW,2BAAX,WAAW,QAEtB;AAED,SAAgB,yBAAyB,CAAC,IAAY;IACpD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW,CAAC,MAAM;YACrB,OAAO,SAAS,CAAC;QACnB;YACE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAOD,SAAgB,qBAAqB;IACnC,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC;QACrC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC,CAAC;AACN,CAAC;AAOY,QAAA,WAAW,GAAG,uBAAuB,CAAC;AACtC,QAAA,UAAU,GAAG,0CAA0C,CAAC;AACxD,QAAA,WAAW,GAAG,cAAI,CAAC,IAAI,CAClC,OAAO,CAAC,GAAG,EAAE,EACb,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAC7C,CAAC;AACW,QAAA,SAAS,GAAG,wBAAwB,CAAC;AACrC,QAAA,gBAAgB,GAAG,0BAA0B,CAAC;AAC9C,QAAA,qBAAqB,GAAG,gCAAgC,CAAC","sourcesContent":["import path from 'path';\n\nexport enum Integration {\n nextjs = 'nextjs',\n}\n\nexport function getIntegrationDescription(type: string): string {\n switch (type) {\n case Integration.nextjs:\n return 'Next.js';\n default:\n throw new Error(`Unknown integration ${type}`);\n }\n}\n\ntype IntegrationChoice = {\n name: string;\n value: string;\n};\n\nexport function getIntegrationChoices(): IntegrationChoice[] {\n return Object.keys(Integration).map((type: string) => ({\n name: getIntegrationDescription(type),\n value: type,\n }));\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\nexport const DEFAULT_URL = 'http://us.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const INSTALL_DIR = path.join(\n process.cwd(),\n process.env.POSTHOG_WIZARD_INSTALL_DIR ?? '',\n);\nexport const CLOUD_URL = 'https://us.posthog.com';\nexport const DEFAULT_HOST_URL = 'https://us.i.posthog.com';\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_API_KEY_';\n"]}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":";;;AAIA,8DAOC;AAOD,sDAKC;AAvBD,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,gCAAiB,CAAA;AACnB,CAAC,EAFW,WAAW,2BAAX,WAAW,QAEtB;AAED,SAAgB,yBAAyB,CAAC,IAAY;IACpD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW,CAAC,MAAM;YACrB,OAAO,SAAS,CAAC;QACnB;YACE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAOD,SAAgB,qBAAqB;IACnC,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,EAAE,yBAAyB,CAAC,IAAI,CAAC;QACrC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC,CAAC;AACN,CAAC;AAOY,QAAA,WAAW,GAAG,uBAAuB,CAAC;AACtC,QAAA,UAAU,GAAG,0CAA0C,CAAC;AACxD,QAAA,SAAS,GAAG,wBAAwB,CAAC;AACrC,QAAA,gBAAgB,GAAG,0BAA0B,CAAC;AAC9C,QAAA,0CAA0C,GAAG,gBAAgB,CAAC;AAC9D,QAAA,kBAAkB,GAAG,gCAAgC,CAAC;AACtD,QAAA,qBAAqB,GAAG,gCAAgC,CAAC","sourcesContent":["export enum Integration {\n nextjs = 'nextjs',\n}\n\nexport function getIntegrationDescription(type: string): string {\n switch (type) {\n case Integration.nextjs:\n return 'Next.js';\n default:\n throw new Error(`Unknown integration ${type}`);\n }\n}\n\ntype IntegrationChoice = {\n name: string;\n value: string;\n};\n\nexport function getIntegrationChoices(): IntegrationChoice[] {\n return Object.keys(Integration).map((type: string) => ({\n name: getIntegrationDescription(type),\n value: type,\n }));\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\nexport const DEFAULT_URL = 'http://us.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const CLOUD_URL = 'https://us.posthog.com';\nexport const DEFAULT_HOST_URL = 'https://us.i.posthog.com';\nexport const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';\nexport const ANALYTICS_HOST_URL = 'https://internal-t.posthog.com';\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_API_KEY_';\n"]}
@@ -5,25 +5,26 @@ const utils_1 = require("./utils");
5
5
  const getNextjsAppRouterDocs = ({ host, language, }) => {
6
6
  return `
7
7
  ==============================
8
- FILE: app/components/PostHogProvider.${language === 'typescript' ? 'tsx' : 'jsx'}
8
+ FILE: PostHogProvider.${language === 'typescript' ? 'tsx' : 'jsx'} (put it somewhere where client files are, like the components folder)
9
+ LOCATION: Wherever other providers are, or the components folder
9
10
  ==============================
10
11
  Changes:
11
12
  - Create a PostHogProvider component that will be imported into the layout file.
12
13
 
13
14
  Example:
14
15
  --------------------------------------------------
15
- 'use client'
16
+ "use client"
16
17
 
17
- import posthog from 'posthog-js'
18
- import { PostHogProvider as PHProvider, usePostHog } from 'posthog-js/react'
19
- import { Suspense, useEffect } from 'react'
18
+ import posthog from "posthog-js"
19
+ import { PostHogProvider as PHProvider, usePostHog } from "posthog-js/react"
20
+ import { Suspense, useEffect } from "react"
20
21
  import { usePathname, useSearchParams } from "next/navigation"
21
22
 
22
23
  export function PostHogProvider({ children }: { children: React.ReactNode }) {
23
24
  useEffect(() => {
24
25
  posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
25
26
  api_host: "/ingest",
26
- ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
27
+ ui_host: "${(0, utils_1.getUiHostFromHost)(host)}",
27
28
  capture_pageview: false, // We capture pageviews manually
28
29
  capture_pageleave: true, // Enable pageleave capture
29
30
  })
@@ -50,7 +51,7 @@ function PostHogPageView() {
50
51
  if (search) {
51
52
  url += "?" + search
52
53
  }
53
- posthog.capture('$pageview', { '$current_url': url })
54
+ posthog.capture("$pageview", { "$current_url": url })
54
55
  }
55
56
  }, [pathname, searchParams, posthog])
56
57
 
@@ -67,7 +68,8 @@ function SuspendedPostHogPageView() {
67
68
  --------------------------------------------------
68
69
 
69
70
  ==============================
70
- FILE: app/layout.${language === 'typescript' ? 'tsx' : 'jsx'}
71
+ FILE: layout.${language === 'typescript' ? 'tsx' : 'jsx'}
72
+ LOCATION: Wherever the root layout is
71
73
  ==============================
72
74
  Changes:
73
75
  - Import the PostHogProvider from the providers file and wrap the app in it.
@@ -75,7 +77,7 @@ Changes:
75
77
  Example:
76
78
  --------------------------------------------------
77
79
  // other imports
78
- import { PostHogProvider } from './components/providers'
80
+ import { PostHogProvider } from "LOCATION_OF_POSTHOG_PROVIDER"
79
81
 
80
82
  export default function RootLayout({ children }) {
81
83
  return (
@@ -93,18 +95,19 @@ export default function RootLayout({ children }) {
93
95
  --------------------------------------------------
94
96
 
95
97
  ==============================
96
- FILE: app/lib/server/posthog.${language === 'typescript' ? 'ts' : 'js'}
98
+ FILE: posthog.${language === 'typescript' ? 'ts' : 'js'}
99
+ LOCATION: Wherever works best given the project structure
97
100
  ==============================
98
101
  Changes:
99
102
  - Initialize the PostHog Node.js client
100
103
 
101
104
  Example:
102
105
  --------------------------------------------------
103
- import { PostHog } from 'posthog-node'
106
+ import { PostHog } from "posthog-node"
104
107
 
105
108
  export default function PostHogClient() {
106
109
  const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
107
- host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
110
+ host: "${host}",
108
111
  flushAt: 1,
109
112
  flushInterval: 0,
110
113
  })
@@ -114,6 +117,7 @@ export default function PostHogClient() {
114
117
 
115
118
  ==============================
116
119
  FILE: next.config.{js,ts,mjs,cjs}
120
+ LOCATION: Wherever the root next config is
117
121
  ==============================
118
122
  Changes:
119
123
  - Add rewrites to the Next.js config to support PostHog, if there are existing rewrites, add the PostHog rewrites to them.
@@ -149,7 +153,8 @@ exports.getNextjsAppRouterDocs = getNextjsAppRouterDocs;
149
153
  const getNextjsPagesRouterDocs = ({ host, language, }) => {
150
154
  return `
151
155
  ==============================
152
- FILE: pages/_app.${language === 'typescript' ? 'tsx' : 'jsx'}
156
+ FILE: _app.${language === 'typescript' ? 'tsx' : 'jsx'}
157
+ LOCATION: Wherever the root _app.${language === 'typescript' ? 'tsx' : 'jsx'} file is
153
158
  ==============================
154
159
  Changes:
155
160
  - Initialize PostHog in _app.js.
@@ -158,25 +163,26 @@ Changes:
158
163
 
159
164
  Example:
160
165
  --------------------------------------------------
161
- import { useEffect } from 'react'
162
- import { Router } from 'next/router'
163
- import posthog from 'posthog-js'
164
- import { PostHogProvider } from 'posthog-js/react'
166
+ import { useEffect } from "react"
167
+ import { Router } from "next/router"
168
+ import posthog from "posthog-js"
169
+ import { PostHogProvider } from "posthog-js/react"
165
170
 
166
171
  export default function App({ Component, pageProps }) {
167
172
  useEffect(() => {
168
173
  posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
169
- api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com',
174
+ api_host: "/ingest",
175
+ ui_host: "${(0, utils_1.getUiHostFromHost)(host)}",
170
176
  loaded: (posthog) => {
171
- if (process.env.NODE_ENV === 'development') posthog.debug()
177
+ if (process.env.NODE_ENV === "development") posthog.debug()
172
178
  },
173
179
  })
174
180
 
175
- const handleRouteChange = () => posthog?.capture('$pageview')
176
- Router.events.on('routeChangeComplete', handleRouteChange)
181
+ const handleRouteChange = () => posthog?.capture("$pageview")
182
+ Router.events.on("routeChangeComplete", handleRouteChange)
177
183
 
178
184
  return () => {
179
- Router.events.off('routeChangeComplete', handleRouteChange)
185
+ Router.events.off("routeChangeComplete", handleRouteChange)
180
186
  }
181
187
  }, [])
182
188
 
@@ -189,18 +195,19 @@ export default function App({ Component, pageProps }) {
189
195
  --------------------------------------------------
190
196
 
191
197
  ==============================
192
- FILE: lib/server/posthog.${language === 'typescript' ? 'ts' : 'js'}
198
+ FILE: posthog.${language === 'typescript' ? 'ts' : 'js'}
199
+ LOCATION: Wherever works best given the project structure
193
200
  ==============================
194
201
  Changes:
195
202
  - Initialize the PostHog Node.js client for server-side tracking.
196
203
 
197
204
  Example:
198
205
  --------------------------------------------------
199
- import { PostHog } from 'posthog-node'
206
+ import { PostHog } from "posthog-node"
200
207
 
201
208
  export default function PostHogClient() {
202
209
  return new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
203
- host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
210
+ host: "${host}",
204
211
  flushAt: 1,
205
212
  flushInterval: 0,
206
213
  })
@@ -209,6 +216,7 @@ export default function PostHogClient() {
209
216
 
210
217
  ==============================
211
218
  FILE: next.config.{js,ts,mjs,cjs}
219
+ LOCATION: Wherever the root next config is
212
220
  ==============================
213
221
  Changes:
214
222
  - Add rewrites to support PostHog tracking.
@@ -1 +1 @@
1
- {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../src/nextjs/docs.ts"],"names":[],"mappings":";;;AAAA,mCAA+C;AAExC,MAAM,sBAAsB,GAAG,CAAC,EACrC,IAAI,EACJ,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO;;uCAE8B,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KACvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA8De,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;+BA0B7B,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAkC9C,IAAA,4BAAoB,EAAC,IAAI,CAAC;;;;wBAI1B,IAAI;;;;wBAIJ,IAAI;;;;;;;;mDAQuB,CAAC;AACpD,CAAC,CAAC;AArJW,QAAA,sBAAsB,0BAqJjC;AAEK,MAAM,wBAAwB,GAAG,CAAC,EACvC,IAAI,EACJ,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO;;mBAEU,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAwCjC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDA8BT,IAAA,4BAAoB,EACzE,IAAI,CACL;kDAC+C,IAAI;kDACJ,IAAI;;;;;;;;CAQrD,CAAC;AACF,CAAC,CAAC;AA5FW,QAAA,wBAAwB,4BA4FnC","sourcesContent":["import { getAssetHostFromHost } from './utils';\n\nexport const getNextjsAppRouterDocs = ({\n host,\n language,\n}: {\n host: string;\n language: 'typescript' | 'javascript';\n}) => {\n return `\n==============================\nFILE: app/components/PostHogProvider.${language === 'typescript' ? 'tsx' : 'jsx'\n }\n==============================\nChanges:\n- Create a PostHogProvider component that will be imported into the layout file.\n\nExample:\n--------------------------------------------------\n'use client'\n\nimport posthog from 'posthog-js'\nimport { PostHogProvider as PHProvider, usePostHog } from 'posthog-js/react'\nimport { Suspense, useEffect } from 'react'\nimport { usePathname, useSearchParams } from \"next/navigation\"\n\nexport function PostHogProvider({ children }: { children: React.ReactNode }) {\n useEffect(() => {\n posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n api_host: \"/ingest\",\n ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,\n capture_pageview: false, // We capture pageviews manually\n capture_pageleave: true, // Enable pageleave capture\n })\n }, [])\n\n return (\n <PHProvider client={posthog}>\n <SuspendedPostHogPageView />\n {children}\n </PHProvider>\n )\n}\n\n\nfunction PostHogPageView() {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const posthog = usePostHog()\n\n useEffect(() => {\n if (pathname && posthog) {\n let url = window.origin + pathname\n const search = searchParams.toString()\n if (search) {\n url += \"?\" + search\n }\n posthog.capture('$pageview', { '$current_url': url })\n }\n }, [pathname, searchParams, posthog])\n\n return null\n}\n\nfunction SuspendedPostHogPageView() {\n return (\n <Suspense fallback={null}>\n <PostHogPageView />\n </Suspense>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: app/layout.${language === 'typescript' ? 'tsx' : 'jsx'}\n==============================\nChanges:\n- Import the PostHogProvider from the providers file and wrap the app in it.\n\nExample:\n--------------------------------------------------\n// other imports\nimport { PostHogProvider } from './components/providers'\n\nexport default function RootLayout({ children }) {\n return (\n <html lang=\"en\">\n <body>\n <PostHogProvider>\n {/* other providers */}\n {children}\n {/* other providers */}\n </PostHogProvider>\n </body>\n </html>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: app/lib/server/posthog.${language === 'typescript' ? 'ts' : 'js'}\n==============================\nChanges:\n- Initialize the PostHog Node.js client\n\nExample:\n--------------------------------------------------\nimport { PostHog } from 'posthog-node'\n\nexport default function PostHogClient() {\n const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n host: process.env.NEXT_PUBLIC_POSTHOG_HOST,\n flushAt: 1,\n flushInterval: 0,\n })\n return posthogClient\n}\n--------------------------------------------------\n\n==============================\nFILE: next.config.{js,ts,mjs,cjs}\n==============================\nChanges:\n- Add rewrites to the Next.js config to support PostHog, if there are existing rewrites, add the PostHog rewrites to them.\n- Add skipTrailingSlashRedirect to the Next.js config to support PostHog trailing slash API requests.\n- This can be of type js, ts, mjs, cjs etc. You should adapt the file according\nExample:\n--------------------------------------------------\nconst nextConfig = {\n // other config\n async rewrites() {\n return [\n {\n source: \"/ingest/static/:path*\",\n destination: \"${getAssetHostFromHost(host)}/static/:path*\",\n },\n {\n source: \"/ingest/:path*\",\n destination: \"${host}/:path*\",\n },\n {\n source: \"/ingest/decide\",\n destination: \"${host}/decide\",\n },\n ];\n },\n // This is required to support PostHog trailing slash API requests\n skipTrailingSlashRedirect: true,\n}\nmodule.exports = nextConfig\n--------------------------------------------------`;\n};\n\nexport const getNextjsPagesRouterDocs = ({\n host,\n language,\n}: {\n host: string;\n language: 'typescript' | 'javascript';\n}) => {\n return `\n==============================\nFILE: pages/_app.${language === 'typescript' ? 'tsx' : 'jsx'}\n==============================\nChanges:\n- Initialize PostHog in _app.js.\n- Wrap the application in PostHogProvider.\n- Manually capture $pageview events.\n\nExample:\n--------------------------------------------------\nimport { useEffect } from 'react'\nimport { Router } from 'next/router'\nimport posthog from 'posthog-js'\nimport { PostHogProvider } from 'posthog-js/react'\n\nexport default function App({ Component, pageProps }) {\n useEffect(() => {\n posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {\n api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com',\n loaded: (posthog) => {\n if (process.env.NODE_ENV === 'development') posthog.debug()\n },\n })\n\n const handleRouteChange = () => posthog?.capture('$pageview')\n Router.events.on('routeChangeComplete', handleRouteChange)\n\n return () => {\n Router.events.off('routeChangeComplete', handleRouteChange)\n }\n }, [])\n\n return (\n <PostHogProvider client={posthog}>\n <Component {...pageProps} />\n </PostHogProvider>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: lib/server/posthog.${language === 'typescript' ? 'ts' : 'js'}\n==============================\nChanges:\n- Initialize the PostHog Node.js client for server-side tracking.\n\nExample:\n--------------------------------------------------\nimport { PostHog } from 'posthog-node'\n\nexport default function PostHogClient() {\n return new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n host: process.env.NEXT_PUBLIC_POSTHOG_HOST,\n flushAt: 1,\n flushInterval: 0,\n })\n}\n--------------------------------------------------\n\n==============================\nFILE: next.config.{js,ts,mjs,cjs}\n==============================\nChanges:\n- Add rewrites to support PostHog tracking.\n- Enable support for PostHog API trailing slash requests.\n\nExample:\n--------------------------------------------------\nconst nextConfig = {\n async rewrites() {\n return [\n { source: \"/ingest/static/:path*\", destination: \"${getAssetHostFromHost(\n host,\n )}/static/:path*\" },\n { source: \"/ingest/:path*\", destination: \"${host}/:path*\" },\n { source: \"/ingest/decide\", destination: \"${host}/decide\" },\n ]\n },\n skipTrailingSlashRedirect: true,\n}\n\nmodule.exports = nextConfig\n--------------------------------------------------\n`;\n};\n"]}
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../src/nextjs/docs.ts"],"names":[],"mappings":";;;AAAA,mCAAkE;AAE3D,MAAM,sBAAsB,GAAG,CAAC,EACrC,IAAI,EACJ,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO;;wBAGL,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KACtC;;;;;;;;;;;;;;;;;;;kBAmBgB,IAAA,yBAAiB,EAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eA4C1B,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA2BxC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;;;;;;;;;aAY1C,IAAI;;;;;;;;;;;;;;;;;;;;;;;;wBAwBO,IAAA,4BAAoB,EAAC,IAAI,CAAC;;;;wBAI1B,IAAI;;;;wBAIJ,IAAI;;;;;;;;mDAQuB,CAAC;AACpD,CAAC,CAAC;AA1JW,QAAA,sBAAsB,0BA0JjC;AAEK,MAAM,wBAAwB,GAAG,CAAC,EACvC,IAAI,EACJ,QAAQ,GAIT,EAAE,EAAE;IACH,OAAO;;aAEI,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;mCAElD,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KACtC;;;;;;;;;;;;;;;;;;kBAkBgB,IAAA,yBAAiB,EAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;gBAuBzB,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;;;;;;;;;aAY1C,IAAI;;;;;;;;;;;;;;;;;;;;yDAoBwC,IAAA,4BAAoB,EACrE,IAAI,CACL;kDAC2C,IAAI;kDACJ,IAAI;;;;;;;;CAQrD,CAAC;AACF,CAAC,CAAC;AAlGW,QAAA,wBAAwB,4BAkGnC","sourcesContent":["import { getAssetHostFromHost, getUiHostFromHost } from './utils';\n\nexport const getNextjsAppRouterDocs = ({\n host,\n language,\n}: {\n host: string;\n language: 'typescript' | 'javascript';\n}) => {\n return `\n==============================\nFILE: PostHogProvider.${\n language === 'typescript' ? 'tsx' : 'jsx'\n } (put it somewhere where client files are, like the components folder)\nLOCATION: Wherever other providers are, or the components folder\n==============================\nChanges:\n- Create a PostHogProvider component that will be imported into the layout file.\n\nExample:\n--------------------------------------------------\n\"use client\"\n\nimport posthog from \"posthog-js\"\nimport { PostHogProvider as PHProvider, usePostHog } from \"posthog-js/react\"\nimport { Suspense, useEffect } from \"react\"\nimport { usePathname, useSearchParams } from \"next/navigation\"\n\nexport function PostHogProvider({ children }: { children: React.ReactNode }) {\n useEffect(() => {\n posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n api_host: \"/ingest\",\n ui_host: \"${getUiHostFromHost(host)}\",\n capture_pageview: false, // We capture pageviews manually\n capture_pageleave: true, // Enable pageleave capture\n })\n }, [])\n\n return (\n <PHProvider client={posthog}>\n <SuspendedPostHogPageView />\n {children}\n </PHProvider>\n )\n}\n\n\nfunction PostHogPageView() {\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const posthog = usePostHog()\n\n useEffect(() => {\n if (pathname && posthog) {\n let url = window.origin + pathname\n const search = searchParams.toString()\n if (search) {\n url += \"?\" + search\n }\n posthog.capture(\"$pageview\", { \"$current_url\": url })\n }\n }, [pathname, searchParams, posthog])\n\n return null\n}\n\nfunction SuspendedPostHogPageView() {\n return (\n <Suspense fallback={null}>\n <PostHogPageView />\n </Suspense>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: layout.${language === 'typescript' ? 'tsx' : 'jsx'}\nLOCATION: Wherever the root layout is\n==============================\nChanges:\n- Import the PostHogProvider from the providers file and wrap the app in it.\n\nExample:\n--------------------------------------------------\n// other imports\nimport { PostHogProvider } from \"LOCATION_OF_POSTHOG_PROVIDER\"\n\nexport default function RootLayout({ children }) {\n return (\n <html lang=\"en\">\n <body>\n <PostHogProvider>\n {/* other providers */}\n {children}\n {/* other providers */}\n </PostHogProvider>\n </body>\n </html>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: posthog.${language === 'typescript' ? 'ts' : 'js'}\nLOCATION: Wherever works best given the project structure\n==============================\nChanges:\n- Initialize the PostHog Node.js client\n\nExample:\n--------------------------------------------------\nimport { PostHog } from \"posthog-node\"\n\nexport default function PostHogClient() {\n const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n host: \"${host}\",\n flushAt: 1,\n flushInterval: 0,\n })\n return posthogClient\n}\n--------------------------------------------------\n\n==============================\nFILE: next.config.{js,ts,mjs,cjs}\nLOCATION: Wherever the root next config is\n==============================\nChanges:\n- Add rewrites to the Next.js config to support PostHog, if there are existing rewrites, add the PostHog rewrites to them.\n- Add skipTrailingSlashRedirect to the Next.js config to support PostHog trailing slash API requests.\n- This can be of type js, ts, mjs, cjs etc. You should adapt the file according\nExample:\n--------------------------------------------------\nconst nextConfig = {\n // other config\n async rewrites() {\n return [\n {\n source: \"/ingest/static/:path*\",\n destination: \"${getAssetHostFromHost(host)}/static/:path*\",\n },\n {\n source: \"/ingest/:path*\",\n destination: \"${host}/:path*\",\n },\n {\n source: \"/ingest/decide\",\n destination: \"${host}/decide\",\n },\n ];\n },\n // This is required to support PostHog trailing slash API requests\n skipTrailingSlashRedirect: true,\n}\nmodule.exports = nextConfig\n--------------------------------------------------`;\n};\n\nexport const getNextjsPagesRouterDocs = ({\n host,\n language,\n}: {\n host: string;\n language: 'typescript' | 'javascript';\n}) => {\n return `\n==============================\nFILE: _app.${language === 'typescript' ? 'tsx' : 'jsx'}\nLOCATION: Wherever the root _app.${\n language === 'typescript' ? 'tsx' : 'jsx'\n } file is\n==============================\nChanges:\n- Initialize PostHog in _app.js.\n- Wrap the application in PostHogProvider.\n- Manually capture $pageview events.\n\nExample:\n--------------------------------------------------\nimport { useEffect } from \"react\"\nimport { Router } from \"next/router\"\nimport posthog from \"posthog-js\"\nimport { PostHogProvider } from \"posthog-js/react\"\n\nexport default function App({ Component, pageProps }) {\n useEffect(() => {\n posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {\n api_host: \"/ingest\",\n ui_host: \"${getUiHostFromHost(host)}\",\n loaded: (posthog) => {\n if (process.env.NODE_ENV === \"development\") posthog.debug()\n },\n })\n\n const handleRouteChange = () => posthog?.capture(\"$pageview\")\n Router.events.on(\"routeChangeComplete\", handleRouteChange)\n\n return () => {\n Router.events.off(\"routeChangeComplete\", handleRouteChange)\n }\n }, [])\n\n return (\n <PostHogProvider client={posthog}>\n <Component {...pageProps} />\n </PostHogProvider>\n )\n}\n--------------------------------------------------\n\n==============================\nFILE: posthog.${language === 'typescript' ? 'ts' : 'js'}\nLOCATION: Wherever works best given the project structure\n==============================\nChanges:\n- Initialize the PostHog Node.js client for server-side tracking.\n\nExample:\n--------------------------------------------------\nimport { PostHog } from \"posthog-node\"\n\nexport default function PostHogClient() {\n return new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n host: \"${host}\",\n flushAt: 1,\n flushInterval: 0,\n })\n}\n--------------------------------------------------\n\n==============================\nFILE: next.config.{js,ts,mjs,cjs}\nLOCATION: Wherever the root next config is\n==============================\nChanges:\n- Add rewrites to support PostHog tracking.\n- Enable support for PostHog API trailing slash requests.\n\nExample:\n--------------------------------------------------\nconst nextConfig = {\n async rewrites() {\n return [\n { source: \"/ingest/static/:path*\", destination: \"${getAssetHostFromHost(\n host,\n )}/static/:path*\" },\n { source: \"/ingest/:path*\", destination: \"${host}/:path*\" },\n { source: \"/ingest/decide\", destination: \"${host}/decide\" },\n ]\n },\n skipTrailingSlashRedirect: true,\n}\n\nmodule.exports = nextConfig\n--------------------------------------------------\n`;\n};\n"]}
@@ -1,9 +1,9 @@
1
1
  import type { WizardOptions } from '../utils/types';
2
2
  import { Integration } from '../lib/constants';
3
3
  export declare function runNextjsWizard(options: WizardOptions): Promise<void>;
4
- export declare function detectNextJs(): Promise<Integration.nextjs | undefined>;
5
- export declare function addOrUpdateEnvironmentVariables({ projectApiKey, host, }: {
4
+ export declare function detectNextJs(options: Pick<WizardOptions, 'installDir'>): Promise<Integration.nextjs | undefined>;
5
+ export declare function addOrUpdateEnvironmentVariables({ projectApiKey, installDir, }: {
6
6
  projectApiKey: string;
7
- host: string;
7
+ installDir: string;
8
8
  }): Promise<void>;
9
- export declare function getDotGitignore(): string | undefined;
9
+ export declare function getDotGitignore({ installDir, }: Pick<WizardOptions, 'installDir'>): string | undefined;
@@ -57,30 +57,31 @@ const constants_1 = require("../lib/constants");
57
57
  const docs_1 = require("./docs");
58
58
  const analytics_1 = require("../utils/analytics");
59
59
  async function runNextjsWizard(options) {
60
- const { telemetryEnabled, forceInstall } = options;
60
+ const { forceInstall } = options;
61
61
  (0, clack_utils_1.printWelcome)({
62
62
  wizardName: 'PostHog Next.js Wizard',
63
- telemetryEnabled,
64
63
  });
65
64
  const aiConsent = await askForAIConsent();
66
65
  if (!aiConsent) {
67
66
  await (0, clack_utils_1.abort)('The Next.js wizard requires AI to get setup right now. Please view the docs to setup Next.js manually instead: https://posthog.com/docs/libraries/next-js', 0);
68
67
  }
69
- const typeScriptDetected = (0, clack_utils_1.isUsingTypeScript)();
68
+ const typeScriptDetected = (0, clack_utils_1.isUsingTypeScript)(options);
70
69
  await (0, clack_utils_1.confirmContinueIfNoOrDirtyGitRepo)();
71
- const packageJson = await (0, clack_utils_1.getPackageDotJson)();
70
+ const packageJson = await (0, clack_utils_1.getPackageDotJson)(options);
72
71
  await (0, clack_utils_1.ensurePackageIsInstalled)(packageJson, 'next', 'Next.js');
73
72
  const nextVersion = (0, package_json_1.getPackageVersion)('next', packageJson);
74
- analytics_1.Analytics.setTag('nextjs-version', (0, utils_1.getNextJsVersionBucket)(nextVersion));
73
+ analytics_1.analytics.setTag('nextjs-version', (0, utils_1.getNextJsVersionBucket)(nextVersion));
75
74
  const { projectApiKey, wizardHash, host } = await (0, clack_utils_1.getOrAskForProjectData)(options);
76
75
  const sdkAlreadyInstalled = (0, package_json_1.hasPackageInstalled)('posthog-js', packageJson);
77
- analytics_1.Analytics.setTag('sdk-already-installed', sdkAlreadyInstalled);
76
+ analytics_1.analytics.setTag('sdk-already-installed', sdkAlreadyInstalled);
78
77
  const { packageManager: packageManagerFromInstallStep } = await (0, clack_utils_1.installPackage)({
79
78
  packageName: 'posthog-js',
80
79
  packageNameDisplayLabel: 'posthog-js',
81
80
  alreadyInstalled: !!packageJson?.dependencies?.['posthog-js'],
82
81
  forceInstall,
83
82
  askBeforeUpdating: false,
83
+ installDir: options.installDir,
84
+ integration: constants_1.Integration.nextjs,
84
85
  });
85
86
  await (0, clack_utils_1.installPackage)({
86
87
  packageName: 'posthog-node',
@@ -89,9 +90,16 @@ async function runNextjsWizard(options) {
89
90
  alreadyInstalled: !!packageJson?.dependencies?.['posthog-node'],
90
91
  forceInstall,
91
92
  askBeforeUpdating: false,
93
+ installDir: options.installDir,
94
+ integration: constants_1.Integration.nextjs,
95
+ });
96
+ const router = await (0, utils_1.getNextJsRouter)(options);
97
+ const relevantFiles = await getRelevantFilesForNextJs(options);
98
+ analytics_1.analytics.capture('wizard interaction', {
99
+ action: 'detected relevant files',
100
+ integration: constants_1.Integration.nextjs,
101
+ number_of_files: relevantFiles.length,
92
102
  });
93
- const router = await (0, utils_1.getNextJsRouter)();
94
- const relevantFiles = await getRelevantFilesForNextJs();
95
103
  const installationDocumentation = getInstallationDocumentation({
96
104
  router,
97
105
  host,
@@ -103,13 +111,23 @@ async function runNextjsWizard(options) {
103
111
  installationDocumentation,
104
112
  wizardHash,
105
113
  });
114
+ analytics_1.analytics.capture('wizard interaction', {
115
+ action: 'detected files to change',
116
+ integration: constants_1.Integration.nextjs,
117
+ files: filesToChange,
118
+ });
106
119
  const changes = [];
107
120
  for (const filePath of filesToChange) {
108
121
  const fileChangeSpinner = clack_1.default.spinner();
122
+ analytics_1.analytics.capture('wizard interaction', {
123
+ action: 'processing file',
124
+ integration: constants_1.Integration.nextjs,
125
+ file: filePath,
126
+ });
109
127
  try {
110
128
  let oldContent = undefined;
111
129
  try {
112
- oldContent = await fs.promises.readFile(path_1.default.join(constants_1.INSTALL_DIR, filePath), 'utf8');
130
+ oldContent = await fs.promises.readFile(path_1.default.join(options.installDir, filePath), 'utf8');
113
131
  }
114
132
  catch (readError) {
115
133
  if (readError.code !== 'ENOENT') {
@@ -128,10 +146,15 @@ async function runNextjsWizard(options) {
128
146
  wizardHash,
129
147
  });
130
148
  if (newContent !== oldContent) {
131
- await updateFile({ filePath, oldContent, newContent });
149
+ await updateFile({ filePath, oldContent, newContent }, options);
132
150
  changes.push({ filePath, oldContent, newContent });
133
151
  }
134
152
  fileChangeSpinner.stop(`${oldContent ? 'Updated' : 'Created'} file ${filePath}`);
153
+ analytics_1.analytics.capture('wizard interaction', {
154
+ action: 'processed file',
155
+ integration: constants_1.Integration.nextjs,
156
+ file: filePath,
157
+ });
135
158
  }
136
159
  catch (error) {
137
160
  await (0, clack_utils_1.abort)(`Error processing file ${filePath}`);
@@ -139,16 +162,24 @@ async function runNextjsWizard(options) {
139
162
  }
140
163
  await addOrUpdateEnvironmentVariables({
141
164
  projectApiKey,
142
- host,
165
+ installDir: options.installDir,
166
+ });
167
+ analytics_1.analytics.capture('wizard interaction', {
168
+ action: 'added environment variables',
169
+ integration: constants_1.Integration.nextjs,
170
+ });
171
+ const packageManagerForOutro = packageManagerFromInstallStep ?? (await (0, clack_utils_1.getPackageManager)(options));
172
+ await (0, clack_utils_1.runPrettierIfInstalled)({
173
+ installDir: options.installDir,
174
+ integration: constants_1.Integration.nextjs,
143
175
  });
144
- const packageManagerForOutro = packageManagerFromInstallStep ?? (await (0, clack_utils_1.getPackageManager)());
145
- await (0, clack_utils_1.runPrettierIfInstalled)();
146
176
  clack_1.default.outro(`
147
177
  ${chalk_1.default.green('Successfully installed PostHog!')} ${`\n\n${aiConsent
148
178
  ? `Note: This uses experimental AI to setup your project. It might have got it wrong, pleaes check!\n`
149
179
  : ``}You should validate your setup by (re)starting your dev environment (e.g. ${chalk_1.default.cyan(`${packageManagerForOutro.runScriptCommand} dev`)})`}
150
180
 
151
181
  ${chalk_1.default.dim(`If you encounter any issues, let us know here: ${constants_1.ISSUES_URL}`)}`);
182
+ await analytics_1.analytics.shutdown('success');
152
183
  }
153
184
  async function askForAIConsent() {
154
185
  return await (0, telemetry_1.traceStep)('ask-for-ai-consent', async () => {
@@ -171,7 +202,7 @@ async function askForAIConsent() {
171
202
  return aiConsent;
172
203
  });
173
204
  }
174
- async function getRelevantFilesForNextJs() {
205
+ async function getRelevantFilesForNextJs({ installDir, }) {
175
206
  const filterPatterns = ['**/*.{tsx,ts,jsx,js,mjs,cjs}'];
176
207
  const ignorePatterns = [
177
208
  'node_modules',
@@ -182,13 +213,13 @@ async function getRelevantFilesForNextJs() {
182
213
  'next-env.d.*',
183
214
  ];
184
215
  const filteredFiles = await (0, fast_glob_1.default)(filterPatterns, {
185
- cwd: constants_1.INSTALL_DIR,
216
+ cwd: installDir,
186
217
  ignore: ignorePatterns,
187
218
  });
188
219
  return filteredFiles;
189
220
  }
190
- async function detectNextJs() {
191
- const packageJson = await (0, clack_utils_1.getPackageDotJson)();
221
+ async function detectNextJs(options) {
222
+ const packageJson = await (0, clack_utils_1.getPackageDotJson)(options);
192
223
  const hasNextInstalled = (0, package_json_1.hasPackageInstalled)('next', packageJson);
193
224
  if (hasNextInstalled)
194
225
  return constants_1.Integration.nextjs;
@@ -238,32 +269,38 @@ async function generateFileChanges({ filePath, content, changedFiles, unchangedF
238
269
  });
239
270
  return response.newContent;
240
271
  }
241
- async function updateFile(change) {
242
- const dir = path_1.default.dirname(path_1.default.join(constants_1.INSTALL_DIR, change.filePath));
272
+ async function updateFile(change, { installDir }) {
273
+ const dir = path_1.default.dirname(path_1.default.join(installDir, change.filePath));
243
274
  await fs.promises.mkdir(dir, { recursive: true });
244
- await fs.promises.writeFile(path_1.default.join(constants_1.INSTALL_DIR, change.filePath), change.newContent);
275
+ await fs.promises.writeFile(path_1.default.join(installDir, change.filePath), change.newContent);
245
276
  }
246
- async function addOrUpdateEnvironmentVariables({ projectApiKey, host, }) {
247
- const envVarContent = `# Posthog\nNEXT_PUBLIC_POSTHOG_KEY=${projectApiKey}\nNEXT_PUBLIC_POSTHOG_HOST=${host}\n`;
248
- const dotEnvLocalFilePath = path_1.default.join(constants_1.INSTALL_DIR, '.env.local');
249
- const dotEnvFilePath = path_1.default.join(constants_1.INSTALL_DIR, '.env');
277
+ async function addOrUpdateEnvironmentVariables({ projectApiKey, installDir, }) {
278
+ const envVarContent = `# Posthog\nNEXT_PUBLIC_POSTHOG_KEY=${projectApiKey}`;
279
+ const dotEnvLocalFilePath = path_1.default.join(installDir, '.env.local');
280
+ const dotEnvFilePath = path_1.default.join(installDir, '.env');
250
281
  const targetEnvFilePath = fs.existsSync(dotEnvLocalFilePath)
251
282
  ? dotEnvLocalFilePath
252
283
  : dotEnvFilePath;
253
284
  const dotEnvFileExists = fs.existsSync(targetEnvFilePath);
254
- const relativeEnvFilePath = path_1.default.relative(constants_1.INSTALL_DIR, targetEnvFilePath);
285
+ const relativeEnvFilePath = path_1.default.relative(installDir, targetEnvFilePath);
255
286
  if (dotEnvFileExists) {
256
287
  const dotEnvFileContent = fs.readFileSync(targetEnvFilePath, 'utf8');
257
288
  const hasProjectApiKey = dotEnvFileContent.includes(`NEXT_PUBLIC_POSTHOG_KEY=${projectApiKey}`);
258
- const hasHost = dotEnvFileContent.includes(`NEXT_PUBLIC_POSTHOG_HOST=${host}`);
259
- if (hasProjectApiKey && hasHost) {
289
+ if (hasProjectApiKey) {
260
290
  clack_1.default.log.success(`${chalk_1.default.bold.cyan(relativeEnvFilePath)} already has the necessary environment variables.`);
261
291
  }
262
292
  else {
263
293
  try {
264
- const newContent = dotEnvFileContent
265
- .replace(/^NEXT_PUBLIC_POSTHOG_KEY=.*$/m, `NEXT_PUBLIC_POSTHOG_KEY=${projectApiKey}`)
266
- .replace(/^NEXT_PUBLIC_POSTHOG_HOST=.*$/m, `NEXT_PUBLIC_POSTHOG_HOST=${host}`);
294
+ let newContent = dotEnvFileContent;
295
+ if (dotEnvFileContent.match(/^NEXT_PUBLIC_POSTHOG_KEY=.*$/m)) {
296
+ newContent = dotEnvFileContent.replace(/^NEXT_PUBLIC_POSTHOG_KEY=.*$/m, `NEXT_PUBLIC_POSTHOG_KEY=${projectApiKey}`);
297
+ }
298
+ else {
299
+ if (!dotEnvFileContent.endsWith('\n')) {
300
+ newContent += '\n';
301
+ }
302
+ newContent += envVarContent;
303
+ }
267
304
  await fs.promises.writeFile(targetEnvFilePath, newContent, {
268
305
  encoding: 'utf8',
269
306
  flag: 'w',
@@ -287,7 +324,7 @@ async function addOrUpdateEnvironmentVariables({ projectApiKey, host, }) {
287
324
  clack_1.default.log.warning(`Failed to create ${chalk_1.default.bold.cyan(relativeEnvFilePath)} with environment variables for PostHog. Please add them manually. Error: ${error.message}`);
288
325
  }
289
326
  }
290
- const gitignorePath = getDotGitignore();
327
+ const gitignorePath = getDotGitignore({ installDir });
291
328
  if (gitignorePath) {
292
329
  const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
293
330
  const envFiles = ['.env', '.env.local'];
@@ -309,7 +346,7 @@ async function addOrUpdateEnvironmentVariables({ projectApiKey, host, }) {
309
346
  else {
310
347
  try {
311
348
  const newGitignoreContent = `.env\n.env.local\n`;
312
- await fs.promises.writeFile(path_1.default.join(constants_1.INSTALL_DIR, '.gitignore'), newGitignoreContent, {
349
+ await fs.promises.writeFile(path_1.default.join(installDir, '.gitignore'), newGitignoreContent, {
313
350
  encoding: 'utf8',
314
351
  flag: 'w',
315
352
  });
@@ -320,8 +357,8 @@ async function addOrUpdateEnvironmentVariables({ projectApiKey, host, }) {
320
357
  }
321
358
  }
322
359
  }
323
- function getDotGitignore() {
324
- const gitignorePath = path_1.default.join(constants_1.INSTALL_DIR, '.gitignore');
360
+ function getDotGitignore({ installDir, }) {
361
+ const gitignorePath = path_1.default.join(installDir, '.gitignore');
325
362
  const gitignoreExists = fs.existsSync(gitignorePath);
326
363
  if (gitignoreExists) {
327
364
  return gitignorePath;