@tanstack/create 0.64.0 → 0.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/create-app.js +72 -16
- package/dist/file-helpers.js +14 -0
- package/dist/frameworks/react/add-ons/ai/info.json +1 -1
- package/dist/frameworks/react/add-ons/better-auth/info.json +1 -1
- package/dist/frameworks/react/add-ons/clerk/README.md +42 -1
- package/dist/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +94 -11
- package/dist/frameworks/react/add-ons/clerk/info.json +1 -1
- package/dist/frameworks/react/add-ons/compiler/info.json +1 -1
- package/dist/frameworks/react/add-ons/convex/info.json +1 -1
- package/dist/frameworks/react/add-ons/drizzle/info.json +1 -1
- package/dist/frameworks/react/add-ons/mcp/info.json +1 -1
- package/dist/frameworks/react/add-ons/neon/info.json +1 -1
- package/dist/frameworks/react/add-ons/paraglide/info.json +1 -1
- package/dist/frameworks/react/add-ons/prisma/info.json +1 -1
- package/dist/frameworks/react/add-ons/shadcn/info.json +1 -1
- package/dist/frameworks/react/add-ons/strapi/info.json +1 -1
- package/dist/frameworks/react/add-ons/t3env/info.json +1 -1
- package/dist/frameworks/react/add-ons/workos/info.json +1 -1
- package/dist/frameworks/react/hosts/cloudflare/README.md +11 -0
- package/dist/frameworks/react/hosts/cloudflare/info.json +1 -1
- package/dist/frameworks/react/hosts/netlify/README.md +11 -0
- package/dist/frameworks/react/hosts/netlify/info.json +1 -1
- package/dist/frameworks/react/hosts/nitro/README.md +12 -0
- package/dist/frameworks/react/hosts/nitro/info.json +1 -1
- package/dist/frameworks/react/hosts/railway/README.md +10 -0
- package/dist/frameworks/react/hosts/railway/info.json +1 -1
- package/dist/frameworks/solid/add-ons/better-auth/info.json +1 -1
- package/dist/frameworks/solid/add-ons/convex/info.json +1 -1
- package/dist/frameworks/solid/add-ons/solid-ui/info.json +1 -1
- package/dist/frameworks/solid/add-ons/strapi/info.json +1 -1
- package/dist/frameworks/solid/add-ons/t3env/info.json +1 -1
- package/dist/frameworks/solid/hosts/cloudflare/README.md +11 -0
- package/dist/frameworks/solid/hosts/cloudflare/info.json +1 -1
- package/dist/frameworks/solid/hosts/netlify/README.md +11 -0
- package/dist/frameworks/solid/hosts/netlify/info.json +1 -1
- package/dist/frameworks/solid/hosts/nitro/README.md +12 -0
- package/dist/frameworks/solid/hosts/nitro/info.json +1 -1
- package/dist/frameworks/solid/hosts/railway/README.md +10 -0
- package/dist/frameworks/solid/hosts/railway/info.json +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/intent.js +1 -1
- package/dist/types/file-helpers.d.ts +1 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/create-app.ts +86 -22
- package/src/file-helpers.ts +20 -0
- package/src/frameworks/react/add-ons/ai/info.json +1 -1
- package/src/frameworks/react/add-ons/better-auth/info.json +1 -1
- package/src/frameworks/react/add-ons/clerk/README.md +42 -1
- package/src/frameworks/react/add-ons/clerk/assets/src/routes/demo/clerk.tsx +94 -11
- package/src/frameworks/react/add-ons/clerk/info.json +1 -1
- package/src/frameworks/react/add-ons/compiler/info.json +1 -1
- package/src/frameworks/react/add-ons/convex/info.json +1 -1
- package/src/frameworks/react/add-ons/drizzle/info.json +1 -1
- package/src/frameworks/react/add-ons/mcp/info.json +1 -1
- package/src/frameworks/react/add-ons/neon/info.json +1 -1
- package/src/frameworks/react/add-ons/paraglide/info.json +1 -1
- package/src/frameworks/react/add-ons/prisma/info.json +1 -1
- package/src/frameworks/react/add-ons/shadcn/info.json +1 -1
- package/src/frameworks/react/add-ons/strapi/info.json +1 -1
- package/src/frameworks/react/add-ons/t3env/info.json +1 -1
- package/src/frameworks/react/add-ons/workos/info.json +1 -1
- package/src/frameworks/react/hosts/cloudflare/README.md +11 -0
- package/src/frameworks/react/hosts/cloudflare/info.json +1 -1
- package/src/frameworks/react/hosts/netlify/README.md +11 -0
- package/src/frameworks/react/hosts/netlify/info.json +1 -1
- package/src/frameworks/react/hosts/nitro/README.md +12 -0
- package/src/frameworks/react/hosts/nitro/info.json +1 -1
- package/src/frameworks/react/hosts/railway/README.md +10 -0
- package/src/frameworks/react/hosts/railway/info.json +1 -1
- package/src/frameworks/solid/add-ons/better-auth/info.json +1 -1
- package/src/frameworks/solid/add-ons/convex/info.json +1 -1
- package/src/frameworks/solid/add-ons/solid-ui/info.json +1 -1
- package/src/frameworks/solid/add-ons/strapi/info.json +1 -1
- package/src/frameworks/solid/add-ons/t3env/info.json +1 -1
- package/src/frameworks/solid/hosts/cloudflare/README.md +11 -0
- package/src/frameworks/solid/hosts/cloudflare/info.json +1 -1
- package/src/frameworks/solid/hosts/netlify/README.md +11 -0
- package/src/frameworks/solid/hosts/netlify/info.json +1 -1
- package/src/frameworks/solid/hosts/nitro/README.md +12 -0
- package/src/frameworks/solid/hosts/nitro/info.json +1 -1
- package/src/frameworks/solid/hosts/railway/README.md +10 -0
- package/src/frameworks/solid/hosts/railway/info.json +1 -1
- package/src/index.ts +1 -0
- package/src/integrations/intent.ts +1 -1
- package/tests/create-app.test.ts +95 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## Deploy with Nitro
|
|
2
|
+
|
|
3
|
+
This project uses Nitro as a generic server adapter, so it can run on any Node-compatible host.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run build
|
|
7
|
+
node dist/server/index.mjs
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The build output is a self-contained Node server. To deploy, push the `dist/` directory to your host (Render, Fly.io, your own VPS, etc.) and run the server command above.
|
|
11
|
+
|
|
12
|
+
For host-specific presets (Vercel, Netlify, Cloudflare, AWS Lambda, etc.) and tuning, see https://v3.nitro.build/deploy.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Deploy to Railway
|
|
2
|
+
|
|
3
|
+
This project ships with `nixpacks.toml` so Railway detects the build automatically:
|
|
4
|
+
|
|
5
|
+
1. Push this repo to GitHub
|
|
6
|
+
2. Visit https://railway.com/new and create a project from your repo
|
|
7
|
+
3. In the **Variables** tab, add the entries from `.env.example` with their production values
|
|
8
|
+
4. Railway runs `vite build` and serves from `dist/client`
|
|
9
|
+
|
|
10
|
+
Need a database? Click **+ New** in your project to provision Postgres, MySQL, or Redis directly into the same environment — the connection string is auto-injected as `DATABASE_URL`.
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export { CONFIG_FILE } from './constants.js';
|
|
|
14
14
|
export { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './package-manager.js';
|
|
15
15
|
export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, scanProjectDirectory, scanAddOnDirectories, __testRegisterFramework, __testClearFrameworks, } from './frameworks.js';
|
|
16
16
|
export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfigFile, } from './config-file.js';
|
|
17
|
-
export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
17
|
+
export { cleanUpFiles, cleanUpFileArray, isDemoFilePath, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
18
18
|
export { formatCommand, handleSpecialURL } from './utils.js';
|
|
19
19
|
export { initStarter, compileStarter } from './custom-add-ons/starter.js';
|
|
20
20
|
export { initAddOn, compileAddOn, devAddOn } from './custom-add-ons/add-on.js';
|
|
@@ -12,7 +12,7 @@ export async function setupIntent(environment, targetDir, options) {
|
|
|
12
12
|
message: 'Setting up TanStack Intent skill mappings...',
|
|
13
13
|
});
|
|
14
14
|
try {
|
|
15
|
-
await packageManagerExecute(environment, resolve(targetDir), options.packageManager, '@tanstack/intent', ['install']);
|
|
15
|
+
await packageManagerExecute(environment, resolve(targetDir), options.packageManager, '@tanstack/intent', ['install', '--map']);
|
|
16
16
|
environment.finishStep('setup-intent', 'TanStack Intent configured');
|
|
17
17
|
s.stop('TanStack Intent configured');
|
|
18
18
|
}
|
|
@@ -10,6 +10,7 @@ export declare function getBinaryFile(content: string): string | null;
|
|
|
10
10
|
export declare function toCleanPath(absolutePath: string, baseDir: string): string;
|
|
11
11
|
export declare function relativePath(from: string, to: string, stripExtension?: boolean): string;
|
|
12
12
|
export declare function isDirectory(path: string): boolean;
|
|
13
|
+
export declare function isDemoFilePath(path?: string): boolean;
|
|
13
14
|
export declare function findFilesRecursively(path: string, files: Record<string, string>): void;
|
|
14
15
|
export declare function recursivelyGatherFiles(path: string, includeProjectFiles?: boolean): Promise<Record<string, string>>;
|
|
15
16
|
export declare function recursivelyGatherFilesFromEnvironment(environment: Environment, path: string, includeProjectFiles?: boolean): Promise<Record<string, string>>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { CONFIG_FILE } from './constants.js';
|
|
|
9
9
|
export { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './package-manager.js';
|
|
10
10
|
export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, scanProjectDirectory, scanAddOnDirectories, __testRegisterFramework, __testClearFrameworks, } from './frameworks.js';
|
|
11
11
|
export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfigFile, } from './config-file.js';
|
|
12
|
-
export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
12
|
+
export { cleanUpFiles, cleanUpFileArray, isDemoFilePath, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
13
13
|
export { formatCommand, handleSpecialURL } from './utils.js';
|
|
14
14
|
export { initStarter, compileStarter } from './custom-add-ons/starter.js';
|
|
15
15
|
export { initAddOn, compileAddOn, devAddOn } from './custom-add-ons/add-on.js';
|
package/package.json
CHANGED
package/src/create-app.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename, resolve } from 'node:path'
|
|
2
2
|
|
|
3
|
-
import { isBase64 } from './file-helpers.js'
|
|
3
|
+
import { isBase64, isDemoFilePath } from './file-helpers.js'
|
|
4
4
|
import { formatCommand } from './utils.js'
|
|
5
5
|
import { writeConfigFileToEnvironment } from './config-file.js'
|
|
6
6
|
import {
|
|
@@ -18,26 +18,6 @@ import { runSpecialSteps } from './special-steps/index.js'
|
|
|
18
18
|
|
|
19
19
|
import type { Environment, FileBundleHandler, Options } from './types.js'
|
|
20
20
|
|
|
21
|
-
function isDemoFilePath(path?: string) {
|
|
22
|
-
if (!path) return false
|
|
23
|
-
const normalized = path.replace(/\\/g, '/')
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
normalized.includes('/routes/demo/') ||
|
|
27
|
-
normalized.includes('/routes/example/')
|
|
28
|
-
) {
|
|
29
|
-
return true
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const filename = normalized.split('/').pop() || ''
|
|
33
|
-
return (
|
|
34
|
-
filename.startsWith('demo.') ||
|
|
35
|
-
filename.startsWith('demo-') ||
|
|
36
|
-
filename.startsWith('example.') ||
|
|
37
|
-
filename.startsWith('example-')
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
21
|
function stripExamplesFromOptions(options: Options): Options {
|
|
42
22
|
if (options.includeExamples !== false) {
|
|
43
23
|
return options
|
|
@@ -325,6 +305,87 @@ async function seedEnvValues(environment: Environment, options: Options) {
|
|
|
325
305
|
await environment.writeFile(envLocalPath, envContents)
|
|
326
306
|
}
|
|
327
307
|
|
|
308
|
+
async function writeEnvExample(environment: Environment, options: Options) {
|
|
309
|
+
const envExamplePath = resolve(options.targetDir, '.env.example')
|
|
310
|
+
const existing = environment.exists(envExamplePath)
|
|
311
|
+
? await environment.readFile(envExamplePath)
|
|
312
|
+
: ''
|
|
313
|
+
|
|
314
|
+
const declared = new Set<string>()
|
|
315
|
+
for (const match of existing.matchAll(/^([A-Z_][A-Z0-9_]*)=/gm)) {
|
|
316
|
+
declared.add(match[1])
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const sections: Array<string> = []
|
|
320
|
+
for (const addOn of options.chosenAddOns) {
|
|
321
|
+
const lines: Array<string> = []
|
|
322
|
+
for (const envVar of addOn.envVars || []) {
|
|
323
|
+
if (declared.has(envVar.name)) continue
|
|
324
|
+
declared.add(envVar.name)
|
|
325
|
+
if (envVar.description) {
|
|
326
|
+
const required = envVar.required ? ' (required)' : ''
|
|
327
|
+
lines.push(`# ${envVar.description}${required}`)
|
|
328
|
+
}
|
|
329
|
+
lines.push(`${envVar.name}=`)
|
|
330
|
+
}
|
|
331
|
+
if (lines.length > 0) {
|
|
332
|
+
sections.push(`# ${addOn.name}\n${lines.join('\n')}`)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (sections.length === 0) return
|
|
337
|
+
|
|
338
|
+
const additions = sections.join('\n\n')
|
|
339
|
+
const newContent = existing
|
|
340
|
+
? `${existing.trimEnd()}\n\n${additions}\n`
|
|
341
|
+
: `${additions}\n`
|
|
342
|
+
|
|
343
|
+
await environment.writeFile(envExamplePath, newContent)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const SHIPPING_CATEGORIES = new Set(['auth', 'database', 'orm', 'deploy'])
|
|
347
|
+
|
|
348
|
+
function buildNextSteps(options: Options): string {
|
|
349
|
+
const collectedEnv = new Set(Object.keys(options.envVarValues || {}))
|
|
350
|
+
const listedEnvVars = new Set<string>()
|
|
351
|
+
const envVarLines: Array<string> = []
|
|
352
|
+
const docLines: Array<string> = []
|
|
353
|
+
|
|
354
|
+
for (const addOn of options.chosenAddOns) {
|
|
355
|
+
if (addOn.link && addOn.category && SHIPPING_CATEGORIES.has(addOn.category)) {
|
|
356
|
+
docLines.push(` • ${addOn.name} (${addOn.category}) — ${addOn.link}`)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
for (const envVar of addOn.envVars || []) {
|
|
360
|
+
if (listedEnvVars.has(envVar.name)) continue
|
|
361
|
+
listedEnvVars.add(envVar.name)
|
|
362
|
+
const required = envVar.required ? ' (required)' : ''
|
|
363
|
+
const status = collectedEnv.has(envVar.name)
|
|
364
|
+
? ' — already set from your input'
|
|
365
|
+
: ' — needs a value'
|
|
366
|
+
const desc = envVar.description ? ` — ${envVar.description}` : ''
|
|
367
|
+
envVarLines.push(` • ${envVar.name}${required}${desc}${status}`)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const sections: Array<string> = []
|
|
372
|
+
if (envVarLines.length > 0) {
|
|
373
|
+
sections.push(
|
|
374
|
+
`Environment variables (review/fill in .env.local before deploying):\n${envVarLines.join('\n')}`,
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
if (docLines.length > 0) {
|
|
378
|
+
sections.push(`Docs for the integrations you picked:\n${docLines.join('\n')}`)
|
|
379
|
+
}
|
|
380
|
+
if (options.intent) {
|
|
381
|
+
sections.push(
|
|
382
|
+
`Working with an AI agent? Your agent config (AGENTS.md / CLAUDE.md) was wired up by TanStack Intent\nwith explicit skill mappings for the libraries you installed. Try asking your agent:\n • "migrate this Next.js page to TanStack Start"\n • "add a protected /dashboard route"\n • "show me how to use TanStack Router search params"`,
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return sections.length > 0 ? `\nNext steps:\n\n${sections.join('\n\n')}\n` : ''
|
|
387
|
+
}
|
|
388
|
+
|
|
328
389
|
function report(environment: Environment, options: Options) {
|
|
329
390
|
const warnings: Array<string> = []
|
|
330
391
|
for (const addOn of options.chosenAddOns) {
|
|
@@ -358,6 +419,8 @@ ${environment.getErrors().join('\n')}`
|
|
|
358
419
|
: `% cd ${options.projectName}
|
|
359
420
|
`
|
|
360
421
|
|
|
422
|
+
const nextSteps = buildNextSteps(options)
|
|
423
|
+
|
|
361
424
|
// Use the force luke! :)
|
|
362
425
|
environment.outro(
|
|
363
426
|
`${locationMessage}
|
|
@@ -366,7 +429,7 @@ Use the following commands to start your app:
|
|
|
366
429
|
${cdInstruction}% ${formatCommand(
|
|
367
430
|
getPackageManagerScriptCommand(options.packageManager, ['dev']),
|
|
368
431
|
)}
|
|
369
|
-
|
|
432
|
+
${nextSteps}
|
|
370
433
|
Please read the README.md file for information on testing, styling, adding routes, etc.${errorStatement}`,
|
|
371
434
|
)
|
|
372
435
|
}
|
|
@@ -377,6 +440,7 @@ export async function createApp(environment: Environment, options: Options) {
|
|
|
377
440
|
environment.startRun()
|
|
378
441
|
await writeFiles(environment, effectiveOptions)
|
|
379
442
|
await seedEnvValues(environment, effectiveOptions)
|
|
443
|
+
await writeEnvExample(environment, effectiveOptions)
|
|
380
444
|
await runCommandsAndInstallDependencies(environment, effectiveOptions)
|
|
381
445
|
environment.finishRun()
|
|
382
446
|
|
package/src/file-helpers.ts
CHANGED
|
@@ -112,6 +112,26 @@ export function isDirectory(path: string): boolean {
|
|
|
112
112
|
return statSync(path).isDirectory()
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
export function isDemoFilePath(path?: string): boolean {
|
|
116
|
+
if (!path) return false
|
|
117
|
+
const normalized = path.replace(/\\/g, '/')
|
|
118
|
+
|
|
119
|
+
if (
|
|
120
|
+
normalized.includes('/routes/demo/') ||
|
|
121
|
+
normalized.includes('/routes/example/')
|
|
122
|
+
) {
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const filename = normalized.split('/').pop() || ''
|
|
127
|
+
return (
|
|
128
|
+
filename.startsWith('demo.') ||
|
|
129
|
+
filename.startsWith('demo-') ||
|
|
130
|
+
filename.startsWith('example.') ||
|
|
131
|
+
filename.startsWith('example-')
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
115
135
|
export function findFilesRecursively(
|
|
116
136
|
path: string,
|
|
117
137
|
files: Record<string, string>,
|
|
@@ -1,3 +1,44 @@
|
|
|
1
1
|
## Setting up Clerk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
1. Sign up at [clerk.com](https://clerk.com) and create an application
|
|
4
|
+
2. Copy the **Publishable Key** from the Clerk dashboard
|
|
5
|
+
3. Set it in your `.env.local`:
|
|
6
|
+
```bash
|
|
7
|
+
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
|
|
8
|
+
```
|
|
9
|
+
4. Visit the demo route at `/demo/clerk` once `npm run dev` is running
|
|
10
|
+
|
|
11
|
+
### What's wired up
|
|
12
|
+
|
|
13
|
+
- **`<ClerkProvider>`** at the app root (`src/integrations/clerk/provider.tsx`) handles auth context for the whole tree
|
|
14
|
+
- **`<SignInButton>` / `<UserButton>`** in the header swap based on auth state
|
|
15
|
+
- **`/demo/clerk`** shows Clerk's prebuilt sign-in UI and a signed-in greeting
|
|
16
|
+
|
|
17
|
+
### Protecting a route
|
|
18
|
+
|
|
19
|
+
Wrap any component in `<SignedIn>` / `<SignedOut>`:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { SignedIn, SignedOut, RedirectToSignIn } from '@clerk/clerk-react'
|
|
23
|
+
|
|
24
|
+
function ProtectedPage() {
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
<SignedIn>
|
|
28
|
+
<YourPageContent />
|
|
29
|
+
</SignedIn>
|
|
30
|
+
<SignedOut>
|
|
31
|
+
<RedirectToSignIn />
|
|
32
|
+
</SignedOut>
|
|
33
|
+
</>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For server-side checks (route loaders, server functions), see the Clerk docs on [`auth()`](https://clerk.com/docs/references/backend/auth).
|
|
39
|
+
|
|
40
|
+
### Production checklist
|
|
41
|
+
|
|
42
|
+
- Replace the test keys with **production keys** from a dedicated production Clerk instance
|
|
43
|
+
- Configure your production domain under **Domains** in the Clerk dashboard
|
|
44
|
+
- Set up social providers (Google, GitHub, etc.) under **User & Authentication → Social Connections**
|
|
@@ -1,20 +1,103 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
SignIn,
|
|
4
|
+
SignedIn,
|
|
5
|
+
SignedOut,
|
|
6
|
+
useUser,
|
|
7
|
+
} from '@clerk/clerk-react'
|
|
3
8
|
|
|
4
9
|
export const Route = createFileRoute('/demo/clerk')({
|
|
5
|
-
component:
|
|
10
|
+
component: ClerkDemo,
|
|
6
11
|
})
|
|
7
12
|
|
|
8
|
-
function
|
|
9
|
-
|
|
13
|
+
function ClerkDemo() {
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex justify-center py-10 px-4">
|
|
16
|
+
<div className="w-full max-w-md p-6 space-y-6">
|
|
17
|
+
<SignedOut>
|
|
18
|
+
<div className="space-y-1.5">
|
|
19
|
+
<h1 className="text-lg font-semibold leading-none tracking-tight">
|
|
20
|
+
Sign in to continue
|
|
21
|
+
</h1>
|
|
22
|
+
<p className="text-sm text-neutral-500 dark:text-neutral-400">
|
|
23
|
+
Clerk renders the sign-in UI, manages sessions, and handles social providers for you.
|
|
24
|
+
</p>
|
|
25
|
+
</div>
|
|
26
|
+
<div className="flex justify-center pt-2">
|
|
27
|
+
<SignIn routing="hash" />
|
|
28
|
+
</div>
|
|
29
|
+
<p className="text-xs text-center text-neutral-400 dark:text-neutral-500">
|
|
30
|
+
Built with{' '}
|
|
31
|
+
<a
|
|
32
|
+
href="https://clerk.com"
|
|
33
|
+
target="_blank"
|
|
34
|
+
rel="noopener noreferrer"
|
|
35
|
+
className="font-medium hover:text-neutral-600 dark:hover:text-neutral-300"
|
|
36
|
+
>
|
|
37
|
+
CLERK
|
|
38
|
+
</a>
|
|
39
|
+
.
|
|
40
|
+
</p>
|
|
41
|
+
</SignedOut>
|
|
10
42
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
43
|
+
<SignedIn>
|
|
44
|
+
<SignedInGreeting />
|
|
45
|
+
</SignedIn>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function SignedInGreeting() {
|
|
52
|
+
const { user } = useUser()
|
|
53
|
+
if (!user) return null
|
|
54
|
+
|
|
55
|
+
const email = user.primaryEmailAddress?.emailAddress
|
|
56
|
+
const initial = (user.firstName || email || 'U').charAt(0).toUpperCase()
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className="space-y-6">
|
|
60
|
+
<div className="space-y-1.5">
|
|
61
|
+
<h1 className="text-lg font-semibold leading-none tracking-tight">
|
|
62
|
+
Welcome back
|
|
63
|
+
</h1>
|
|
64
|
+
<p className="text-sm text-neutral-500 dark:text-neutral-400">
|
|
65
|
+
You're signed in as {email}
|
|
66
|
+
</p>
|
|
67
|
+
</div>
|
|
14
68
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
69
|
+
<div className="flex items-center gap-3">
|
|
70
|
+
{user.imageUrl ? (
|
|
71
|
+
<img src={user.imageUrl} alt="" className="h-10 w-10 rounded-full" />
|
|
72
|
+
) : (
|
|
73
|
+
<div className="h-10 w-10 bg-neutral-200 dark:bg-neutral-800 flex items-center justify-center rounded-full">
|
|
74
|
+
<span className="text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
|
75
|
+
{initial}
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
<div className="flex-1 min-w-0">
|
|
80
|
+
<p className="text-sm font-medium truncate">
|
|
81
|
+
{user.firstName} {user.lastName}
|
|
82
|
+
</p>
|
|
83
|
+
<p className="text-xs text-neutral-500 dark:text-neutral-400 truncate">
|
|
84
|
+
{email}
|
|
85
|
+
</p>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
18
88
|
|
|
19
|
-
|
|
89
|
+
<p className="text-xs text-center text-neutral-400 dark:text-neutral-500">
|
|
90
|
+
Manage your account from the avatar in the header. Built with{' '}
|
|
91
|
+
<a
|
|
92
|
+
href="https://clerk.com"
|
|
93
|
+
target="_blank"
|
|
94
|
+
rel="noopener noreferrer"
|
|
95
|
+
className="font-medium hover:text-neutral-600 dark:hover:text-neutral-300"
|
|
96
|
+
>
|
|
97
|
+
CLERK
|
|
98
|
+
</a>
|
|
99
|
+
.
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
20
103
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Compiler",
|
|
3
3
|
"phase": "setup",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Auto-memoize components and hooks (fewer re-renders, no manual useMemo/useCallback).",
|
|
5
5
|
"link": "https://react.dev/learn/react-compiler",
|
|
6
6
|
"modes": ["code-router", "file-router"],
|
|
7
7
|
"type": "add-on",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "MCP",
|
|
3
3
|
"phase": "setup",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Expose your app as an MCP server so AI clients (Claude, Cursor) can call into it.",
|
|
5
5
|
"link": "https://mcp.dev",
|
|
6
6
|
"modes": ["file-router"],
|
|
7
7
|
"type": "add-on",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Prisma",
|
|
3
|
-
"description": "
|
|
3
|
+
"description": "Type-safe database client with schema migrations (Postgres, MySQL, SQLite, MongoDB).",
|
|
4
4
|
"phase": "add-on",
|
|
5
5
|
"type": "add-on",
|
|
6
6
|
"category": "orm",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Deploy to Cloudflare Workers
|
|
2
|
+
|
|
3
|
+
This project uses the Cloudflare Vite plugin (configured in `vite.config.ts`) and `wrangler.jsonc`:
|
|
4
|
+
|
|
5
|
+
1. Install Wrangler: `npm install -g wrangler`
|
|
6
|
+
2. Authenticate: `wrangler login`
|
|
7
|
+
3. Deploy: `npx wrangler deploy`
|
|
8
|
+
|
|
9
|
+
For production env vars, run `wrangler secret put MY_VAR` for each secret listed in `.env.example`. Public (non-secret) vars go in `wrangler.jsonc` under `vars`.
|
|
10
|
+
|
|
11
|
+
KV, D1, R2, and Durable Object bindings are configured in `wrangler.jsonc` — see https://developers.cloudflare.com/workers/wrangler/configuration/.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Cloudflare",
|
|
3
|
-
"description": "Cloudflare
|
|
3
|
+
"description": "Deploy to Cloudflare Workers (edge runtime, KV/D1/R2 bindings).",
|
|
4
4
|
"link": "https://developers.cloudflare.com/workers/vite-plugin/",
|
|
5
5
|
"phase": "add-on",
|
|
6
6
|
"modes": ["file-router", "code-router"],
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Deploy to Netlify
|
|
2
|
+
|
|
3
|
+
This project ships with `netlify.toml` configured for a Netlify site:
|
|
4
|
+
|
|
5
|
+
1. Push this repo to GitHub
|
|
6
|
+
2. Visit https://app.netlify.com/start and import the repo
|
|
7
|
+
3. Netlify auto-detects the build (`vite build` → `dist/client`)
|
|
8
|
+
4. Open **Site settings → Environment variables** and add anything from `.env.example` that needs a real value in production
|
|
9
|
+
5. Trigger the first deploy
|
|
10
|
+
|
|
11
|
+
Server functions and API routes run on Netlify Functions. For lower-latency request handling, see Netlify Edge Functions: https://docs.netlify.com/edge-functions/overview.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## Deploy with Nitro
|
|
2
|
+
|
|
3
|
+
This project uses Nitro as a generic server adapter, so it can run on any Node-compatible host.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run build
|
|
7
|
+
node dist/server/index.mjs
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The build output is a self-contained Node server. To deploy, push the `dist/` directory to your host (Render, Fly.io, your own VPS, etc.) and run the server command above.
|
|
11
|
+
|
|
12
|
+
For host-specific presets (Vercel, Netlify, Cloudflare, AWS Lambda, etc.) and tuning, see https://v3.nitro.build/deploy.
|