@tanstack/create 0.60.0 → 0.61.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 (103) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/create-app.js +7 -5
  3. package/dist/file-helpers.js +13 -1
  4. package/dist/frameworks/react/add-ons/ai/info.json +0 -5
  5. package/dist/frameworks/react/add-ons/ai/package.json +0 -1
  6. package/dist/frameworks/{solid/add-ons/better-auth/README.md → react/add-ons/better-auth/README.md.ejs} +2 -2
  7. package/dist/frameworks/react/add-ons/better-auth/assets/_dot_env.local.append.ejs +3 -0
  8. package/dist/frameworks/react/add-ons/better-auth/assets/src/integrations/better-auth/header-user.tsx +3 -1
  9. package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/demo/better-auth.tsx +3 -1
  10. package/dist/frameworks/react/add-ons/convex/README.md.ejs +4 -0
  11. package/dist/frameworks/react/add-ons/drizzle/assets/src/routes/demo/{drizzle.tsx → drizzle.tsx.ejs} +3 -3
  12. package/dist/frameworks/react/add-ons/neon/assets/_dot_env.example.append +2 -2
  13. package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.ts +1 -1
  14. package/dist/frameworks/react/add-ons/neon/assets/src/db.ts +2 -2
  15. package/dist/frameworks/react/add-ons/posthog/README.md +9 -0
  16. package/dist/frameworks/react/add-ons/posthog/assets/_dot_env.local.append +4 -0
  17. package/dist/frameworks/react/add-ons/posthog/assets/src/integrations/posthog/provider.tsx +20 -0
  18. package/dist/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx +93 -0
  19. package/dist/frameworks/react/add-ons/posthog/files.json +5 -0
  20. package/dist/frameworks/react/add-ons/posthog/info.json +28 -0
  21. package/dist/frameworks/react/add-ons/posthog/package.json +6 -0
  22. package/dist/frameworks/react/add-ons/prisma/assets/src/routes/demo/{prisma.tsx → prisma.tsx.ejs} +3 -3
  23. package/dist/frameworks/react/add-ons/prisma/package.json.ejs +1 -1
  24. package/dist/frameworks/react/add-ons/sentry/package.json +1 -1
  25. package/dist/frameworks/react/add-ons/tanstack-query/info.json +1 -1
  26. package/dist/frameworks/react/hosts/nitro/info.json +1 -1
  27. package/dist/frameworks/react/hosts/railway/info.json +1 -1
  28. package/dist/frameworks/react/project/base/README.md.ejs +1 -1
  29. package/dist/frameworks/react/project/base/package.json +1 -1
  30. package/dist/frameworks/react/project/base/vite.config.ts.ejs +1 -1
  31. package/dist/frameworks/{react/add-ons/better-auth/README.md → solid/add-ons/better-auth/README.md.ejs} +2 -2
  32. package/dist/frameworks/solid/add-ons/better-auth/assets/_dot_env.local.append.ejs +3 -0
  33. package/dist/frameworks/solid/add-ons/better-auth/assets/src/integrations/better-auth/header-user.tsx +3 -1
  34. package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/demo.better-auth.tsx +3 -1
  35. package/dist/frameworks/solid/add-ons/convex/README.md.ejs +4 -0
  36. package/{src/frameworks/solid/add-ons/solid-ui/README.md → dist/frameworks/solid/add-ons/solid-ui/README.md.ejs} +1 -1
  37. package/dist/frameworks/solid/add-ons/solid-ui/info.json +1 -5
  38. package/dist/frameworks/solid/project/base/README.md.ejs +1 -1
  39. package/dist/frameworks.js +6 -0
  40. package/dist/package-manager.js +29 -0
  41. package/dist/template-file.js +8 -1
  42. package/dist/types/custom-add-ons/add-on.d.ts +2 -1
  43. package/dist/types/package-manager.d.ts +7 -0
  44. package/dist/types/types.d.ts +21 -15
  45. package/dist/types/utils.d.ts +2 -0
  46. package/dist/types.js +2 -0
  47. package/dist/utils.js +6 -0
  48. package/package.json +1 -1
  49. package/src/create-app.ts +9 -6
  50. package/src/file-helpers.ts +12 -1
  51. package/src/frameworks/react/add-ons/ai/info.json +0 -5
  52. package/src/frameworks/react/add-ons/ai/package.json +0 -1
  53. package/src/frameworks/react/add-ons/better-auth/{README.md → README.md.ejs} +2 -2
  54. package/src/frameworks/react/add-ons/better-auth/assets/_dot_env.local.append.ejs +3 -0
  55. package/src/frameworks/react/add-ons/better-auth/assets/src/integrations/better-auth/header-user.tsx +3 -1
  56. package/src/frameworks/react/add-ons/better-auth/assets/src/routes/demo/better-auth.tsx +3 -1
  57. package/src/frameworks/react/add-ons/convex/README.md.ejs +4 -0
  58. package/src/frameworks/react/add-ons/drizzle/assets/src/routes/demo/{drizzle.tsx → drizzle.tsx.ejs} +3 -3
  59. package/src/frameworks/react/add-ons/neon/assets/_dot_env.example.append +2 -2
  60. package/src/frameworks/react/add-ons/neon/assets/neon-vite-plugin.ts +1 -1
  61. package/src/frameworks/react/add-ons/neon/assets/src/db.ts +2 -2
  62. package/src/frameworks/react/add-ons/posthog/README.md +9 -0
  63. package/src/frameworks/react/add-ons/posthog/assets/_dot_env.local.append +4 -0
  64. package/src/frameworks/react/add-ons/posthog/assets/src/integrations/posthog/provider.tsx +20 -0
  65. package/src/frameworks/react/add-ons/posthog/assets/src/routes/demo/posthog.tsx +93 -0
  66. package/src/frameworks/react/add-ons/posthog/files.json +5 -0
  67. package/src/frameworks/react/add-ons/posthog/info.json +28 -0
  68. package/src/frameworks/react/add-ons/posthog/package.json +6 -0
  69. package/src/frameworks/react/add-ons/prisma/assets/src/routes/demo/{prisma.tsx → prisma.tsx.ejs} +3 -3
  70. package/src/frameworks/react/add-ons/prisma/package.json.ejs +1 -1
  71. package/src/frameworks/react/add-ons/sentry/package.json +1 -1
  72. package/src/frameworks/react/add-ons/tanstack-query/info.json +1 -1
  73. package/src/frameworks/react/hosts/nitro/info.json +1 -1
  74. package/src/frameworks/react/hosts/railway/info.json +1 -1
  75. package/src/frameworks/react/project/base/README.md.ejs +1 -1
  76. package/src/frameworks/react/project/base/package.json +1 -1
  77. package/src/frameworks/react/project/base/vite.config.ts.ejs +1 -1
  78. package/src/frameworks/solid/add-ons/better-auth/{README.md → README.md.ejs} +2 -2
  79. package/src/frameworks/solid/add-ons/better-auth/assets/_dot_env.local.append.ejs +3 -0
  80. package/src/frameworks/solid/add-ons/better-auth/assets/src/integrations/better-auth/header-user.tsx +3 -1
  81. package/src/frameworks/solid/add-ons/better-auth/assets/src/routes/demo.better-auth.tsx +3 -1
  82. package/src/frameworks/solid/add-ons/convex/README.md.ejs +4 -0
  83. package/{dist/frameworks/solid/add-ons/solid-ui/README.md → src/frameworks/solid/add-ons/solid-ui/README.md.ejs} +1 -1
  84. package/src/frameworks/solid/add-ons/solid-ui/info.json +1 -5
  85. package/src/frameworks/solid/project/base/README.md.ejs +1 -1
  86. package/src/frameworks.ts +8 -0
  87. package/src/package-manager.ts +37 -0
  88. package/src/template-file.ts +14 -0
  89. package/src/types.ts +2 -0
  90. package/src/utils.ts +8 -0
  91. package/tests/file-helper.test.ts +6 -0
  92. package/tests/package-manager.test.ts +159 -0
  93. package/tests/template-file.test.ts +13 -0
  94. package/dist/frameworks/react/add-ons/ai/assets/src/lib/ai-devtools.tsx +0 -3
  95. package/dist/frameworks/react/add-ons/better-auth/assets/_dot_env.local.append +0 -3
  96. package/dist/frameworks/react/add-ons/convex/README.md +0 -4
  97. package/dist/frameworks/solid/add-ons/better-auth/assets/_dot_env.local.append +0 -3
  98. package/dist/frameworks/solid/add-ons/convex/README.md +0 -4
  99. package/src/frameworks/react/add-ons/ai/assets/src/lib/ai-devtools.tsx +0 -3
  100. package/src/frameworks/react/add-ons/better-auth/assets/_dot_env.local.append +0 -3
  101. package/src/frameworks/react/add-ons/convex/README.md +0 -4
  102. package/src/frameworks/solid/add-ons/better-auth/assets/_dot_env.local.append +0 -3
  103. package/src/frameworks/solid/add-ons/convex/README.md +0 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @tanstack/create
2
2
 
3
+ ## 0.61.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add PostHog add-on ([#317](https://github.com/TanStack/cli/pull/317))
8
+
9
+ ## 0.60.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Pin the React Sentry add-on to `@sentry/tanstackstart-react@10.34.0` to avoid a Nitro production build failure introduced in newer Sentry versions. ([`ab740ed`](https://github.com/TanStack/cli/commit/ab740ed2c5510a3266065aa98c8afe3093ea0034))
14
+
3
15
  ## 0.60.0
4
16
 
5
17
  ### Minor Changes
@@ -2,7 +2,7 @@ import { basename, resolve } from 'node:path';
2
2
  import { isBase64 } from './file-helpers.js';
3
3
  import { formatCommand } from './utils.js';
4
4
  import { writeConfigFileToEnvironment } from './config-file.js';
5
- import { getPackageManagerScriptCommand, packageManagerInstall, } from './package-manager.js';
5
+ import { getPackageManagerScriptCommand, packageManagerInstall, translateExecuteCommand, } from './package-manager.js';
6
6
  import { createPackageJSON } from './package-json.js';
7
7
  import { createTemplateFile } from './template-file.js';
8
8
  import { installShadcnComponents } from './integrations/shadcn.js';
@@ -134,16 +134,17 @@ async function runCommandsAndInstallDependencies(environment, options) {
134
134
  for (const phase of ['setup', 'add-on', 'example']) {
135
135
  for (const addOn of options.chosenAddOns.filter((addOn) => addOn.phase === phase && addOn.command && addOn.command.command)) {
136
136
  s.start(`Running commands for ${addOn.name}...`);
137
- const cmd = formatCommand({
137
+ const translated = translateExecuteCommand(options.packageManager, {
138
138
  command: addOn.command.command,
139
139
  args: addOn.command.args || [],
140
140
  });
141
+ const cmd = formatCommand(translated);
141
142
  environment.startStep({
142
143
  id: 'run-commands',
143
144
  type: 'command',
144
145
  message: cmd,
145
146
  });
146
- await environment.execute(addOn.command.command, addOn.command.args || [], options.targetDir, { inherit: true });
147
+ await environment.execute(translated.command, translated.args, options.targetDir, { inherit: true });
147
148
  environment.finishStep('run-commands', 'Setup commands complete');
148
149
  s.stop(`${addOn.name} commands complete`);
149
150
  }
@@ -153,16 +154,17 @@ async function runCommandsAndInstallDependencies(environment, options) {
153
154
  options.starter.command &&
154
155
  options.starter.command.command) {
155
156
  s.start(`Setting up starter ${options.starter.name}...`);
156
- const cmd = formatCommand({
157
+ const starterTranslated = translateExecuteCommand(options.packageManager, {
157
158
  command: options.starter.command.command,
158
159
  args: options.starter.command.args || [],
159
160
  });
161
+ const cmd = formatCommand(starterTranslated);
160
162
  environment.startStep({
161
163
  id: 'run-starter-command',
162
164
  type: 'command',
163
165
  message: cmd,
164
166
  });
165
- await environment.execute(options.starter.command.command, options.starter.command.args || [], options.targetDir, { inherit: true });
167
+ await environment.execute(starterTranslated.command, starterTranslated.args, options.targetDir, { inherit: true });
166
168
  environment.finishStep('run-starter-command', 'Starter command complete');
167
169
  s.stop(`${options.starter.name} commands complete`);
168
170
  }
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
3
3
  import { basename, extname, resolve } from 'node:path';
4
4
  import parseGitignore from 'parse-gitignore';
5
5
  import ignore from 'ignore';
6
+ import { hasDrive, stripDrive } from './utils';
6
7
  const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico'];
7
8
  export function readFileHelper(path) {
8
9
  if (isBinaryFile(path)) {
@@ -35,7 +36,18 @@ export function toCleanPath(absolutePath, baseDir) {
35
36
  // Normalize both paths to use forward slashes for consistent comparison
36
37
  const normalizedPath = absolutePath.replace(/\\/g, '/');
37
38
  const normalizedBase = baseDir.replace(/\\/g, '/');
38
- let cleanPath = normalizedPath.replace(normalizedBase, '');
39
+ let cleanPath = normalizedPath;
40
+ if (normalizedPath.startsWith(normalizedBase)) {
41
+ cleanPath = normalizedPath.slice(normalizedBase.length);
42
+ }
43
+ else if (hasDrive(normalizedPath) !== hasDrive(normalizedBase)) {
44
+ // Handle paths that are missing the Windows drive letter (e.g. memfs on Windows)
45
+ const pathNoDrive = stripDrive(normalizedPath);
46
+ const baseNoDrive = stripDrive(normalizedBase);
47
+ if (pathNoDrive.startsWith(baseNoDrive)) {
48
+ cleanPath = pathNoDrive.slice(baseNoDrive.length);
49
+ }
50
+ }
39
51
  // Handle leading path separator
40
52
  if (cleanPath.startsWith('/')) {
41
53
  cleanPath = cleanPath.slice(1);
@@ -36,11 +36,6 @@
36
36
  "type": "header-user",
37
37
  "path": "src/components/demo-AIAssistant.tsx",
38
38
  "jsName": "TanChatAIAssistant"
39
- },
40
- {
41
- "type": "devtools",
42
- "path": "src/lib/ai-devtools.tsx",
43
- "jsName": "AiDevtools"
44
39
  }
45
40
  ],
46
41
  "dependsOn": ["store"],
@@ -7,7 +7,6 @@
7
7
  "@tanstack/ai-ollama": "latest",
8
8
  "@tanstack/ai-openai": "latest",
9
9
  "@tanstack/ai-react": "latest",
10
- "@tanstack/react-ai-devtools": "latest",
11
10
  "highlight.js": "^11.11.1",
12
11
  "streamdown": "^1.6.5",
13
12
  "lucide-react": "^0.544.0",
@@ -3,7 +3,7 @@
3
3
  1. Generate and set the `BETTER_AUTH_SECRET` environment variable in your `.env.local`:
4
4
 
5
5
  ```bash
6
- npx @better-auth/cli secret
6
+ <%- getPackageManagerExecuteScript('@better-auth/cli', ['secret']) %>
7
7
  ```
8
8
 
9
9
  2. Visit the [Better Auth documentation](https://www.better-auth.com) to unlock the full potential of authentication in your app.
@@ -28,5 +28,5 @@ export const auth = betterAuth({
28
28
  Then run migrations:
29
29
 
30
30
  ```bash
31
- npx @better-auth/cli migrate
31
+ <%- getPackageManagerExecuteScript('@better-auth/cli', ['migrate']) %>
32
32
  ```
@@ -0,0 +1,3 @@
1
+ # Better Auth configuration
2
+ BETTER_AUTH_URL=http://localhost:3000
3
+ BETTER_AUTH_SECRET= # Generate a secret key: `<%- getPackageManagerExecuteScript('@better-auth/cli', ['secret']) %>`
@@ -23,7 +23,9 @@ export default function BetterAuthHeader() {
23
23
  </div>
24
24
  )}
25
25
  <button
26
- onClick={() => authClient.signOut()}
26
+ onClick={() => {
27
+ void authClient.signOut()
28
+ }}
27
29
  className="flex-1 h-9 px-4 text-sm font-medium bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-50 border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-50 dark:hover:bg-neutral-800 transition-colors"
28
30
  >
29
31
  Sign out
@@ -57,7 +57,9 @@ function BetterAuthDemo() {
57
57
  </div>
58
58
 
59
59
  <button
60
- onClick={() => authClient.signOut()}
60
+ onClick={() => {
61
+ void authClient.signOut()
62
+ }}
61
63
  className="w-full h-9 px-4 text-sm font-medium border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
62
64
  >
63
65
  Sign out
@@ -0,0 +1,4 @@
1
+ ## Setting up Convex
2
+
3
+ - Set the `VITE_CONVEX_URL` and `CONVEX_DEPLOYMENT` environment variables in your `.env.local`. (Or run `<%- getPackageManagerExecuteScript('convex', ['init']) %>` to set them automatically.)
4
+ - Run `<%- getPackageManagerExecuteScript('convex', ['dev']) %>` to start the Convex server.
@@ -163,19 +163,19 @@ function DemoDrizzle() {
163
163
  <li>
164
164
  Run:{' '}
165
165
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
166
- npx drizzle-kit generate
166
+ <%- getPackageManagerExecuteScript('drizzle-kit', ['generate']) %>
167
167
  </code>
168
168
  </li>
169
169
  <li>
170
170
  Run:{' '}
171
171
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
172
- npx drizzle-kit migrate
172
+ <%- getPackageManagerExecuteScript('drizzle-kit', ['migrate']) %>
173
173
  </code>
174
174
  </li>
175
175
  <li>
176
176
  Optional:{' '}
177
177
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
178
- npx drizzle-kit studio
178
+ <%- getPackageManagerExecuteScript('drizzle-kit', ['studio']) %>
179
179
  </code>
180
180
  </li>
181
181
  </ol>
@@ -1,4 +1,4 @@
1
1
  # These will be automatically created by Neon Launchpad (https://neon.new).
2
2
  # You will also need to
3
- VITE_DATABASE_URL=
4
- VITE_DATABASE_URL_POOLER=
3
+ DATABASE_URL=
4
+ DATABASE_URL_POOLER=
@@ -6,5 +6,5 @@ export default postgresPlugin({
6
6
  path: 'db/init.sql',
7
7
  },
8
8
  referrer: 'create-tanstack',
9
- dotEnvKey: 'VITE_DATABASE_URL',
9
+ dotEnvKey: 'DATABASE_URL',
10
10
  })
@@ -3,11 +3,11 @@ import { neon } from '@neondatabase/serverless'
3
3
  let client: ReturnType<typeof neon>
4
4
 
5
5
  export async function getClient() {
6
- if (!process.env.VITE_DATABASE_URL) {
6
+ if (!process.env.DATABASE_URL) {
7
7
  return undefined
8
8
  }
9
9
  if (!client) {
10
- client = await neon(process.env.VITE_DATABASE_URL!)
10
+ client = await neon(process.env.DATABASE_URL!)
11
11
  }
12
12
  return client
13
13
  }
@@ -0,0 +1,9 @@
1
+ ## Setting up PostHog
2
+
3
+ 1. Create a PostHog account at [posthog.com](https://posthog.com)
4
+ 2. Get your Project API Key from [Project Settings](https://app.posthog.com/project/settings)
5
+ 3. Set `VITE_POSTHOG_KEY` in your `.env.local`
6
+
7
+ ### Optional Configuration
8
+
9
+ - `VITE_POSTHOG_HOST` - Set this if you're using PostHog Cloud EU (`https://eu.i.posthog.com`) or self-hosting
@@ -0,0 +1,4 @@
1
+ # PostHog configuration, get your key from https://app.posthog.com/project/settings
2
+ VITE_POSTHOG_KEY=phc_xxx
3
+ # Optional: PostHog API host (for self-hosted or EU cloud)
4
+ # VITE_POSTHOG_HOST=https://us.i.posthog.com
@@ -0,0 +1,20 @@
1
+ import posthog from 'posthog-js'
2
+ import { PostHogProvider as BasePostHogProvider } from '@posthog/react'
3
+ import type { ReactNode } from 'react'
4
+
5
+ if (typeof window !== 'undefined' && import.meta.env.VITE_POSTHOG_KEY) {
6
+ posthog.init(import.meta.env.VITE_POSTHOG_KEY, {
7
+ api_host: import.meta.env.VITE_POSTHOG_HOST || 'https://us.i.posthog.com',
8
+ person_profiles: 'identified_only',
9
+ capture_pageview: false,
10
+ defaults: '2025-11-30',
11
+ })
12
+ }
13
+
14
+ interface PostHogProviderProps {
15
+ children: ReactNode
16
+ }
17
+
18
+ export default function PostHogProvider({ children }: PostHogProviderProps) {
19
+ return <BasePostHogProvider client={posthog}>{children}</BasePostHogProvider>
20
+ }
@@ -0,0 +1,93 @@
1
+ import { createFileRoute, Link } from '@tanstack/react-router'
2
+ import { usePostHog } from '@posthog/react'
3
+ import { useState } from 'react'
4
+
5
+ export const Route = createFileRoute('/demo/posthog')({
6
+ component: PostHogDemo,
7
+ })
8
+
9
+ function PostHogDemo() {
10
+ const posthog = usePostHog()
11
+ const [eventCount, setEventCount] = useState(0)
12
+ const posthogKey = import.meta.env.VITE_POSTHOG_KEY
13
+ const isConfigured = Boolean(posthogKey) && posthogKey !== 'phc_xxx'
14
+
15
+ const trackEvent = (
16
+ eventName: string,
17
+ properties?: Record<string, unknown>,
18
+ ) => {
19
+ posthog.capture(eventName, properties)
20
+ setEventCount((c) => c + 1)
21
+ }
22
+
23
+ return (
24
+ <div className="min-h-screen bg-gray-900 text-white p-8">
25
+ <div className="max-w-md mx-auto">
26
+ <h1 className="text-3xl font-bold mb-6">PostHog Demo</h1>
27
+
28
+ {!isConfigured && (
29
+ <div className="mb-4 p-4 bg-yellow-900/50 border border-yellow-600 rounded-lg">
30
+ <p className="text-yellow-200 text-sm">
31
+ <strong>Warning:</strong> VITE_POSTHOG_KEY is not configured.
32
+ Events won't be sent to PostHog. Add it to your{' '}
33
+ <code className="bg-yellow-900 px-1 rounded">.env</code> file.
34
+ </p>
35
+ </div>
36
+ )}
37
+
38
+ <div className="bg-gray-800 rounded-lg p-6">
39
+ <p className="text-gray-400 mb-4">
40
+ Click the button below to send events to PostHog. Check your PostHog
41
+ dashboard to see them appear in real-time.
42
+ </p>
43
+
44
+ <button
45
+ onClick={() => trackEvent('button_clicked', { button: 'demo' })}
46
+ className="w-full bg-cyan-600 hover:bg-cyan-700 px-4 py-3 rounded font-medium"
47
+ >
48
+ Track Click
49
+ </button>
50
+
51
+ {isConfigured && (
52
+ <div className="mt-6 p-4 bg-gray-700 rounded">
53
+ <p className="text-sm text-gray-400">Events sent this session:</p>
54
+ <p className="text-4xl font-bold text-cyan-400">{eventCount}</p>
55
+ </div>
56
+ )}
57
+ </div>
58
+
59
+ <p className="mt-4 text-sm text-gray-400">
60
+ Open your{' '}
61
+ <a
62
+ href="https://app.posthog.com/events"
63
+ target="_blank"
64
+ rel="noopener noreferrer"
65
+ className="text-cyan-400 hover:text-cyan-300 underline"
66
+ >
67
+ PostHog Events
68
+ </a>{' '}
69
+ page to see these events appear.
70
+ </p>
71
+
72
+ <p className="mt-2 text-sm text-gray-400">
73
+ Learn more in the{' '}
74
+ <a
75
+ href="https://posthog.com/docs/libraries/react"
76
+ target="_blank"
77
+ rel="noopener noreferrer"
78
+ className="text-cyan-400 hover:text-cyan-300 underline"
79
+ >
80
+ PostHog React docs
81
+ </a>
82
+ .
83
+ </p>
84
+
85
+ <div className="mt-8">
86
+ <Link to="/" className="text-cyan-400 hover:text-cyan-300">
87
+ &larr; Back to Home
88
+ </Link>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ )
93
+ }
@@ -0,0 +1,5 @@
1
+ [
2
+ "src/integrations/posthog/provider.tsx",
3
+ "src/routes/demo/posthog.tsx",
4
+ "_dot_env.local.append"
5
+ ]
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "PostHog",
3
+ "description": "Product analytics, session replay, and feature flags",
4
+ "phase": "add-on",
5
+ "modes": ["file-router"],
6
+ "type": "add-on",
7
+ "category": "analytics",
8
+ "color": "#1D4AFF",
9
+ "priority": 20,
10
+ "link": "https://posthog.com",
11
+ "tailwind": true,
12
+ "routes": [
13
+ {
14
+ "icon": "BarChart",
15
+ "url": "/demo/posthog",
16
+ "name": "PostHog",
17
+ "path": "src/routes/demo/posthog.tsx",
18
+ "jsName": "PostHogDemo"
19
+ }
20
+ ],
21
+ "integrations": [
22
+ {
23
+ "type": "provider",
24
+ "jsName": "PostHogProvider",
25
+ "path": "src/integrations/posthog/provider.tsx"
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": {
3
+ "posthog-js": "^1.335.4",
4
+ "@posthog/react": "^1.7.0"
5
+ }
6
+ }
@@ -162,19 +162,19 @@ function DemoPrisma() {
162
162
  <li>
163
163
  Run:{' '}
164
164
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
165
- npx prisma generate
165
+ <%- getPackageManagerExecuteScript('prisma', ['generate']) %>
166
166
  </code>
167
167
  </li>
168
168
  <li>
169
169
  Run:{' '}
170
170
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
171
- npx prisma db push
171
+ <%- getPackageManagerExecuteScript('prisma', ['db', 'push']) %>
172
172
  </code>
173
173
  </li>
174
174
  <li>
175
175
  Optional:{' '}
176
176
  <code className="px-2 py-1 rounded bg-black/30 text-purple-300">
177
- npx prisma studio
177
+ <%- getPackageManagerExecuteScript('prisma', ['studio']) %>
178
178
  </code>
179
179
  </li>
180
180
  </ol>
@@ -11,7 +11,7 @@
11
11
  "tsx": "^4.20.6"
12
12
  },
13
13
  "scripts": {<% if (addOnOption.prisma.database === 'postgres') { %>
14
- "post-cta-init": "npx create-db@latest --user-agent tanstack/tsrouter",<% } %>
14
+ "post-cta-init": "<%- getPackageManagerExecuteScript('create-db@latest', ['--user-agent', 'tanstack/tsrouter']) %>",<% } %>
15
15
  "db:generate": "dotenv -e .env.local -- prisma generate",
16
16
  "db:push": "dotenv -e .env.local -- prisma db push",
17
17
  "db:migrate": "dotenv -e .env.local -- prisma migrate dev",
@@ -5,7 +5,7 @@
5
5
  "start": "node --import ./.output/server/instrument.server.mjs .output/server/index.mjs"
6
6
  },
7
7
  "dependencies": {
8
- "@sentry/tanstackstart-react": "^10.22.0",
8
+ "@sentry/tanstackstart-react": "^10.34.0",
9
9
  "dotenv-cli": "^11.0.0"
10
10
  }
11
11
  }
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "integrations": [
21
21
  {
22
- "type": "root-provider",
22
+ "type": "provider",
23
23
  "path": "src/integrations/tanstack-query/root-provider.tsx",
24
24
  "jsName": "TanStackQueryProvider"
25
25
  },
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "type": "vite-plugin",
15
15
  "import": "import { nitro } from 'nitro/vite'",
16
- "code": "nitro()"
16
+ "code": "nitro({ rollupConfig: { external: [/^@sentry\\//] } })"
17
17
  }
18
18
  ],
19
19
  "default": true
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "type": "vite-plugin",
15
15
  "import": "import { nitro } from 'nitro/vite'",
16
- "code": "nitro()"
16
+ "code": "nitro({ rollupConfig: { external: [/^@sentry\\//] } })"
17
17
  }
18
18
  ]
19
19
  }
@@ -52,7 +52,7 @@ This project uses [eslint](https://eslint.org/) and [prettier](https://prettier.
52
52
  ```
53
53
  <% } %>
54
54
  <% for(const addon of addOns.filter(addon => addon.readme)) { %>
55
- <%- addon.readme %>
55
+ <%- addon.readmeIsEjs ? renderTemplate(addon.readme) : addon.readme %>
56
56
  <% } %>
57
57
 
58
58
  ## Routing
@@ -17,7 +17,7 @@
17
17
  "lucide-react": "^0.561.0",
18
18
  "react": "^19.2.0",
19
19
  "react-dom": "^19.2.0",
20
- "vite-tsconfig-paths": "^6.0.2"
20
+ "vite-tsconfig-paths": "^5.1.4"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@tanstack/devtools-vite": "^0.3.11",
@@ -6,7 +6,7 @@ import { paraglideVitePlugin } from "@inlang/paraglide-js"
6
6
  import { tanstackStart } from '@tanstack/react-start/plugin/vite';
7
7
  import viteReact from '@vitejs/plugin-react'
8
8
  import viteTsConfigPaths from 'vite-tsconfig-paths'
9
- import { fileURLToPath, URL } from 'url'
9
+ import { fileURLToPath, URL } from 'node:url'
10
10
  import tailwindcss from "@tailwindcss/vite"
11
11
  <% for(const integration of integrations.filter(i => i.type === 'vite-plugin')) { %><%- integrationImportContent(integration) %>
12
12
  <% } %>
@@ -3,7 +3,7 @@
3
3
  1. Generate and set the `BETTER_AUTH_SECRET` environment variable in your `.env.local`:
4
4
 
5
5
  ```bash
6
- npx @better-auth/cli secret
6
+ <%- getPackageManagerExecuteScript('@better-auth/cli', ['secret']) %>
7
7
  ```
8
8
 
9
9
  2. Visit the [Better Auth documentation](https://www.better-auth.com) to unlock the full potential of authentication in your app.
@@ -28,5 +28,5 @@ export const auth = betterAuth({
28
28
  Then run migrations:
29
29
 
30
30
  ```bash
31
- npx @better-auth/cli migrate
31
+ <%- getPackageManagerExecuteScript('@better-auth/cli', ['migrate']) %>
32
32
  ```
@@ -0,0 +1,3 @@
1
+ # Better Auth configuration
2
+ BETTER_AUTH_URL=http://localhost:3000
3
+ BETTER_AUTH_SECRET= # Generate a secret key: `<%- getPackageManagerExecuteScript('@better-auth/cli', ['secret']) %>`
@@ -38,7 +38,9 @@ export default function BetterAuthHeader() {
38
38
  {(image) => <img src={image()} alt="" class="h-8 w-8" />}
39
39
  </Show>
40
40
  <button
41
- onClick={() => authClient.signOut()}
41
+ onClick={() => {
42
+ void authClient.signOut();
43
+ }}
42
44
  class="flex-1 h-9 px-4 text-sm font-medium bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-50 border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-50 dark:hover:bg-neutral-800 transition-colors"
43
45
  >
44
46
  Sign out
@@ -210,7 +210,9 @@ function BetterAuthDemo() {
210
210
  </div>
211
211
 
212
212
  <button
213
- onClick={() => authClient.signOut()}
213
+ onClick={() => {
214
+ void authClient.signOut();
215
+ }}
214
216
  class="w-full h-9 px-4 text-sm font-medium border border-neutral-300 dark:border-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors"
215
217
  >
216
218
  Sign out
@@ -0,0 +1,4 @@
1
+ ## Setting up Convex
2
+
3
+ - Set the `VITE_CONVEX_URL` and `CONVEX_DEPLOYMENT` environment variables in your `.env.local`. (Or run `<%- getPackageManagerExecuteScript('convex', ['init']) %>` to set them automatically.)
4
+ - Run `<%- getPackageManagerExecuteScript('convex', ['dev']) %>` to start the Convex server.
@@ -5,5 +5,5 @@ This installation of Solid-UI follows the manual instructions but was modified t
5
5
  To install the components, run the following command (this install button):
6
6
 
7
7
  ```bash
8
- npx solidui-cli@latest add button
8
+ <%- getPackageManagerExecuteScript('solidui-cli@latest', ['add', 'button']) %>
9
9
  ```
@@ -6,9 +6,5 @@
6
6
  "modes": ["file-router", "code-router"],
7
7
  "type": "add-on",
8
8
  "category": "styling",
9
- "color": "#000000",
10
- "command": {
11
- "command": "npx",
12
- "args": ["solidui-cli@latest", "add", "button", "input"]
13
- }
9
+ "color": "#000000"
14
10
  }
@@ -31,7 +31,7 @@ If you prefer not to use Tailwind CSS:
31
31
  4. Uninstall the packages: `<%= getPackageManagerAddScript('@tailwindcss/vite tailwindcss', true) %>`
32
32
 
33
33
  <% for(const addon of addOns.filter(addon => addon.readme)) { %>
34
- <%- addon.readme %>
34
+ <%- addon.readmeIsEjs ? renderTemplate(addon.readme) : addon.readme %>
35
35
  <% } %>
36
36
 
37
37
  ## Routing
@@ -37,9 +37,14 @@ export function scanAddOnDirectories(addOnsDirectories) {
37
37
  packageTemplate = readFileSync(resolve(addOnsBase, dir, 'package.json.ejs'), 'utf-8');
38
38
  }
39
39
  let readme;
40
+ let readmeIsEjs = false;
40
41
  if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
41
42
  readme = readFileSync(resolve(addOnsBase, dir, 'README.md'), 'utf-8');
42
43
  }
44
+ else if (existsSync(resolve(addOnsBase, dir, 'README.md.ejs'))) {
45
+ readme = readFileSync(resolve(addOnsBase, dir, 'README.md.ejs'), 'utf-8');
46
+ readmeIsEjs = true;
47
+ }
43
48
  let smallLogo;
44
49
  if (existsSync(resolve(addOnsBase, dir, 'small-logo.svg'))) {
45
50
  smallLogo = readFileSync(resolve(addOnsBase, dir, 'small-logo.svg'), 'utf-8');
@@ -65,6 +70,7 @@ export function scanAddOnDirectories(addOnsDirectories) {
65
70
  packageAdditions,
66
71
  packageTemplate,
67
72
  readme,
73
+ readmeIsEjs,
68
74
  files,
69
75
  smallLogo,
70
76
  getFiles,