@asynx/create-asynx-next-app 1.0.4 → 1.0.6

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 (43) hide show
  1. package/create-asynx-next-app-wrapper/index.js +3 -0
  2. package/create-asynx-next-app-wrapper/package.json +12 -0
  3. package/package.json +1 -1
  4. package/templates/advanced/.env.example +23 -0
  5. package/templates/advanced/README.md +148 -0
  6. package/templates/advanced/next.config.mjs +14 -0
  7. package/templates/advanced/package.json +1 -1
  8. package/templates/advanced/postcss.config.mjs +6 -0
  9. package/templates/advanced/src/app/app/billing/page.tsx +57 -0
  10. package/templates/advanced/src/app/app/layout.tsx +25 -0
  11. package/templates/advanced/src/app/app/page.tsx +36 -0
  12. package/templates/advanced/src/app/app/settings/page.tsx +50 -0
  13. package/templates/advanced/src/app/auth/login/page.tsx +41 -0
  14. package/templates/advanced/src/app/auth/signup/page.tsx +45 -0
  15. package/templates/advanced/src/app/globals.css +151 -8
  16. package/templates/advanced/src/app/layout.tsx +19 -18
  17. package/templates/advanced/src/app/page.tsx +25 -8
  18. package/templates/advanced/src/lib/api/client.ts +67 -0
  19. package/templates/advanced/src/lib/api/config/app.ts +19 -0
  20. package/templates/advanced/src/lib/api/config/constants.ts +38 -0
  21. package/templates/advanced/src/lib/api/features/analytics/lib/analytics-service.ts +26 -0
  22. package/templates/advanced/src/lib/api/features/app-shell/components/app-header.tsx +18 -0
  23. package/templates/advanced/src/lib/api/features/app-shell/components/app-sidebar.tsx +38 -0
  24. package/templates/advanced/src/lib/api/features/auth/lib/auth-service.ts +36 -0
  25. package/templates/advanced/src/lib/api/features/billing/lib/billing-service.ts +38 -0
  26. package/templates/advanced/src/types/index.ts +21 -0
  27. package/templates/advanced/tsconfig.json +14 -11
  28. package/templates/standard/README.md +53 -0
  29. package/templates/standard/package.json +1 -1
  30. package/templates/standard/postcss.config.mjs +6 -0
  31. package/templates/standard/src/app/(dashboard)/dashboard/page.tsx +45 -0
  32. package/templates/standard/src/app/(dashboard)/layout.tsx +30 -0
  33. package/templates/standard/src/app/(public)/layout.tsx +16 -0
  34. package/templates/standard/src/app/(public)/login/page.tsx +33 -0
  35. package/templates/standard/src/app/globals.css +151 -1
  36. package/templates/standard/src/app/layout.tsx +21 -1
  37. package/templates/standard/src/app/page.tsx +22 -3
  38. package/templates/standard/src/lib/api.ts +37 -0
  39. package/templates/standard/src/lib/constants.ts +14 -0
  40. package/templates/standard/tsconfig.json +12 -11
  41. package/templates/starter/package.json +1 -1
  42. package/templates/starter/src/app/globals.css +1 -0
  43. package/templates/advanced/next-env.d.ts +0 -4
@@ -1,18 +1,19 @@
1
- import './globals.css';
2
-
3
- export const metadata = {
4
- title: 'Asynx App',
5
- description: 'Generated by create-asynx-next-app',
6
- };
7
-
8
- export default function RootLayout({
9
- children,
10
- }: {
11
- children: React.ReactNode;
12
- }) {
13
- return (
14
- <html lang="en">
15
- <body>{children}</body>
16
- </html>
17
- );
18
- }
1
+ import type React from "react"
2
+ import "./globals.css"
3
+
4
+ export const metadata = {
5
+ title: "Asynx SaaS",
6
+ description: "Production-ready SaaS template",
7
+ }
8
+
9
+ export default function RootLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode
13
+ }) {
14
+ return (
15
+ <html lang="en">
16
+ <body>{children}</body>
17
+ </html>
18
+ )
19
+ }
@@ -1,8 +1,25 @@
1
- export default function HomePage() {
2
- return (
3
- <main style={{ padding: '2rem' }}>
4
- <h1>🚀 Welcome to your Asynx Next.js App</h1>
5
- <p>This project was generated using create-asynx-next-app.</p>
6
- </main>
7
- );
8
- }
1
+ // Landing page - public facing
2
+ // In advanced apps, this is often separate from the app shell
3
+
4
+ import Link from "next/link"
5
+
6
+ export default function LandingPage() {
7
+ return (
8
+ <main className="min-h-screen">
9
+ <section className="container mx-auto px-6 py-20 text-center">
10
+ <h1 className="text-5xl font-bold mb-6">Welcome to Your SaaS Platform</h1>
11
+ <p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto">
12
+ Built with a scalable, production-ready architecture
13
+ </p>
14
+ <div className="flex gap-4 justify-center">
15
+ <Link href="/app" className="px-6 py-3 bg-foreground text-background rounded-md hover:opacity-90">
16
+ Get Started
17
+ </Link>
18
+ <Link href="/auth/login" className="px-6 py-3 border rounded-md hover:bg-muted">
19
+ Sign In
20
+ </Link>
21
+ </div>
22
+ </section>
23
+ </main>
24
+ )
25
+ }
@@ -0,0 +1,67 @@
1
+ // Shared infrastructure - API client
2
+ // Centralized HTTP client for all features
3
+
4
+ export class ApiError extends Error {
5
+ constructor(message: string, public status: number, public data?: unknown) {
6
+ super(message);
7
+ this.name = 'ApiError';
8
+ }
9
+ }
10
+
11
+ export class ApiClient {
12
+ private baseUrl: string;
13
+
14
+ constructor(baseUrl = '/api') {
15
+ this.baseUrl = baseUrl;
16
+ }
17
+
18
+ private async request<T>(
19
+ endpoint: string,
20
+ options?: RequestInit,
21
+ ): Promise<T> {
22
+ const url = `${this.baseUrl}${endpoint}`;
23
+
24
+ const response = await fetch(url, {
25
+ ...options,
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ ...options?.headers,
29
+ },
30
+ });
31
+
32
+ if (!response.ok) {
33
+ const error = await response.json().catch(() => ({}));
34
+ throw new ApiError(
35
+ error.message || 'Request failed',
36
+ response.status,
37
+ error,
38
+ );
39
+ }
40
+
41
+ return response.json();
42
+ }
43
+
44
+ async get<T>(endpoint: string): Promise<T> {
45
+ return this.request<T>(endpoint, { method: 'GET' });
46
+ }
47
+
48
+ async post<T>(endpoint: string, data?: unknown): Promise<T> {
49
+ return this.request<T>(endpoint, {
50
+ method: 'POST',
51
+ body: data ? JSON.stringify(data) : undefined,
52
+ });
53
+ }
54
+
55
+ async put<T>(endpoint: string, data?: unknown): Promise<T> {
56
+ return this.request<T>(endpoint, {
57
+ method: 'PUT',
58
+ body: data ? JSON.stringify(data) : undefined,
59
+ });
60
+ }
61
+
62
+ async delete<T>(endpoint: string): Promise<T> {
63
+ return this.request<T>(endpoint, { method: 'DELETE' });
64
+ }
65
+ }
66
+
67
+ export const apiClient = new ApiClient();
@@ -0,0 +1,19 @@
1
+ // Shared infrastructure - App configuration
2
+ // Environment-aware configuration
3
+
4
+ export const appConfig = {
5
+ name: 'Your SaaS',
6
+ description: 'Production-ready SaaS template',
7
+ url: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
8
+ api: {
9
+ baseUrl: process.env.NEXT_PUBLIC_API_URL || '/api',
10
+ },
11
+ features: {
12
+ auth: true,
13
+ billing: true,
14
+ analytics: true,
15
+ },
16
+ } as const;
17
+
18
+ export const isProduction = process.env.NODE_ENV === 'production';
19
+ export const isDevelopment = process.env.NODE_ENV === 'development';
@@ -0,0 +1,38 @@
1
+ // Shared infrastructure - Constants
2
+ // Application-wide constants
3
+
4
+ export const ROUTES = {
5
+ // Public routes
6
+ HOME: '/',
7
+ LOGIN: '/auth/login',
8
+ SIGNUP: '/auth/signup',
9
+
10
+ // App routes
11
+ APP: '/app',
12
+ DASHBOARD: '/app',
13
+ BILLING: '/app/billing',
14
+ SETTINGS: '/app/settings',
15
+ ANALYTICS: '/app/analytics',
16
+ } as const;
17
+
18
+ export const API_ROUTES = {
19
+ AUTH_LOGIN: '/api/auth/login',
20
+ AUTH_SIGNUP: '/api/auth/signup',
21
+ AUTH_LOGOUT: '/api/auth/logout',
22
+ USER_PROFILE: '/api/user/profile',
23
+ BILLING_SUBSCRIPTION: '/api/billing/subscription',
24
+ } as const;
25
+
26
+ export const SUBSCRIPTION_PLANS = {
27
+ FREE: { name: 'Free', price: 0, features: ['Basic features'] },
28
+ PRO: {
29
+ name: 'Pro',
30
+ price: 49,
31
+ features: ['All features', 'Priority support'],
32
+ },
33
+ ENTERPRISE: {
34
+ name: 'Enterprise',
35
+ price: 199,
36
+ features: ['Custom everything'],
37
+ },
38
+ } as const;
@@ -0,0 +1,26 @@
1
+ // Analytics feature - Service layer
2
+ // Track events and metrics
3
+
4
+ export type AnalyticsEvent = {
5
+ name: string
6
+ properties?: Record<string, unknown>
7
+ }
8
+
9
+ export class AnalyticsService {
10
+ track(event: AnalyticsEvent) {
11
+ // TODO: Send to analytics provider
12
+ console.log("Analytics event:", event)
13
+ }
14
+
15
+ identify(userId: string, traits?: Record<string, unknown>) {
16
+ // TODO: Identify user
17
+ console.log("Identify user:", userId, traits)
18
+ }
19
+
20
+ page(name: string) {
21
+ // TODO: Track page view
22
+ console.log("Page view:", name)
23
+ }
24
+ }
25
+
26
+ export const analytics = new AnalyticsService()
@@ -0,0 +1,18 @@
1
+ // App shell feature - Header component
2
+
3
+ export function AppHeader() {
4
+ return (
5
+ <header className="border-b px-6 py-4">
6
+ <div className="flex items-center justify-between">
7
+ <div>
8
+ <input type="search" placeholder="Search..." className="px-4 py-2 border rounded-md w-80" />
9
+ </div>
10
+
11
+ <div className="flex items-center gap-4">
12
+ <button className="p-2 hover:bg-muted rounded-md">🔔</button>
13
+ <button className="p-2 hover:bg-muted rounded-md">👤</button>
14
+ </div>
15
+ </div>
16
+ </header>
17
+ )
18
+ }
@@ -0,0 +1,38 @@
1
+ // App shell feature - Sidebar component
2
+ // This is part of the core app navigation infrastructure
3
+
4
+ import Link from "next/link"
5
+
6
+ export function AppSidebar() {
7
+ const navigation = [
8
+ { name: "Dashboard", href: "/app", icon: "📊" },
9
+ { name: "Analytics", href: "/app/analytics", icon: "📈" },
10
+ { name: "Billing", href: "/app/billing", icon: "💳" },
11
+ { name: "Settings", href: "/app/settings", icon: "⚙️" },
12
+ ]
13
+
14
+ return (
15
+ <aside className="w-64 border-r flex flex-col">
16
+ <div className="p-6 border-b">
17
+ <h1 className="text-xl font-bold">Your SaaS</h1>
18
+ </div>
19
+
20
+ <nav className="flex-1 p-4">
21
+ <ul className="space-y-2">
22
+ {navigation.map((item) => (
23
+ <li key={item.name}>
24
+ <Link href={item.href} className="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-muted">
25
+ <span>{item.icon}</span>
26
+ <span>{item.name}</span>
27
+ </Link>
28
+ </li>
29
+ ))}
30
+ </ul>
31
+ </nav>
32
+
33
+ <div className="p-4 border-t">
34
+ <button className="w-full px-3 py-2 text-left hover:bg-muted rounded-md">Sign Out</button>
35
+ </div>
36
+ </aside>
37
+ )
38
+ }
@@ -0,0 +1,36 @@
1
+ // Auth feature - Service layer
2
+ // Business logic for authentication
3
+
4
+ export class AuthService {
5
+ async login(email: string, password: string) {
6
+ // TODO: Implement actual authentication
7
+ // This is a placeholder structure
8
+ console.log("Login attempt:", email)
9
+
10
+ // Example: call your auth API
11
+ // const response = await fetch('/api/auth/login', {
12
+ // method: 'POST',
13
+ // body: JSON.stringify({ email, password })
14
+ // });
15
+
16
+ return { success: true }
17
+ }
18
+
19
+ async signup(email: string, password: string, name: string) {
20
+ // TODO: Implement signup
21
+ console.log("Signup attempt:", email, name)
22
+ return { success: true }
23
+ }
24
+
25
+ async logout() {
26
+ // TODO: Implement logout
27
+ console.log("Logout")
28
+ }
29
+
30
+ async getCurrentUser() {
31
+ // TODO: Get current user session
32
+ return null
33
+ }
34
+ }
35
+
36
+ export const authService = new AuthService()
@@ -0,0 +1,38 @@
1
+ // Billing feature - Service layer
2
+ // Business logic for subscription and payments
3
+
4
+ export type SubscriptionPlan = "free" | "pro" | "enterprise"
5
+
6
+ export interface Subscription {
7
+ plan: SubscriptionPlan
8
+ status: "active" | "canceled" | "past_due"
9
+ currentPeriodEnd: Date
10
+ }
11
+
12
+ export class BillingService {
13
+ async getSubscription(): Promise<Subscription | null> {
14
+ // TODO: Fetch from your billing provider (Stripe, etc.)
15
+ return {
16
+ plan: "pro",
17
+ status: "active",
18
+ currentPeriodEnd: new Date("2024-01-01"),
19
+ }
20
+ }
21
+
22
+ async updateSubscription(plan: SubscriptionPlan) {
23
+ // TODO: Update subscription via API
24
+ console.log("Updating to plan:", plan)
25
+ }
26
+
27
+ async cancelSubscription() {
28
+ // TODO: Cancel subscription
29
+ console.log("Canceling subscription")
30
+ }
31
+
32
+ async getInvoices() {
33
+ // TODO: Fetch invoice history
34
+ return []
35
+ }
36
+ }
37
+
38
+ export const billingService = new BillingService()
@@ -0,0 +1,21 @@
1
+ export type User = {
2
+ id: string;
3
+ email: string;
4
+ name: string;
5
+ role: 'user' | 'admin';
6
+ createdAt: Date;
7
+ };
8
+
9
+ export type ApiResponse<T> = {
10
+ data: T;
11
+ message?: string;
12
+ };
13
+
14
+ export type PaginatedResponse<T> = {
15
+ data: T[];
16
+ pagination: {
17
+ page: number;
18
+ limit: number;
19
+ total: number;
20
+ };
21
+ };
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2022",
3
+ "target": "ES2020",
4
4
  "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": false,
5
+ "allowJs": true,
6
6
  "skipLibCheck": true,
7
7
  "strict": true,
8
8
  "noEmit": true,
@@ -11,16 +11,19 @@
11
11
  "moduleResolution": "bundler",
12
12
  "resolveJsonModule": true,
13
13
  "isolatedModules": true,
14
- "jsx": "react-jsx",
14
+ "jsx": "preserve",
15
15
  "incremental": true,
16
- "plugins": [{ "name": "next" }]
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./src/*"],
23
+ "@/features/*": ["./src/features/*"],
24
+ "@/lib/*": ["./src/lib/*"]
25
+ }
17
26
  },
18
- "include": [
19
- "next-env.d.ts",
20
- "**/*.ts",
21
- "**/*.tsx",
22
- ".next/types/**/*.ts",
23
- ".next/dev/types/**/*.ts"
24
- ],
27
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25
28
  "exclude": ["node_modules"]
26
29
  }
@@ -0,0 +1,53 @@
1
+ # Standard Template
2
+
3
+ This template is designed for **dashboards, content platforms, and early-stage startups**.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ src/
9
+ ├── app/
10
+ │ ├── (public)/ # Public routes (landing, login, signup)
11
+ │ │ ├── login/
12
+ │ │ └── layout.tsx
13
+ │ ├── (dashboard)/ # Authenticated routes
14
+ │ │ ├── dashboard/
15
+ │ │ └── layout.tsx
16
+ │ ├── layout.tsx # Root layout
17
+ │ ├── page.tsx # Homepage
18
+ │ └── globals.css
19
+ ├── components/
20
+ │ ├── ui/ # Reusable UI components
21
+ │ │ ├── button.tsx
22
+ │ │ └── card.tsx
23
+ │ └── layout/ # Layout components
24
+ │ ├── header.tsx
25
+ │ └── footer.tsx
26
+ ├── lib/
27
+ │ ├── api.ts # API client utilities
28
+ │ └── constants.ts # App constants
29
+ └── utils/ # Utility functions
30
+ ```
31
+
32
+ ## Key Features
33
+
34
+ - **Route Groups**: Separate public and authenticated layouts
35
+ - **Component Library**: Basic UI components to get started
36
+ - **API Client**: Centralized API utilities
37
+ - **Layout Hierarchy**: Header, footer, and sidebar examples
38
+ - **TypeScript**: Full type safety
39
+
40
+ ## Getting Started
41
+
42
+ 1. Customize the layouts in \`app/(public)\` and \`app/(dashboard)\`
43
+ 2. Add your UI components in \`components/ui\`
44
+ 3. Configure API endpoints in \`lib/constants.ts\`
45
+ 4. Build your features!
46
+
47
+ ## Auth-Ready Structure
48
+
49
+ This template is structured to easily integrate authentication:
50
+ - Public routes for unauthenticated users
51
+ - Dashboard routes for authenticated users
52
+ - Add middleware for route protection when ready
53
+ ```
@@ -13,7 +13,7 @@
13
13
  "react-dom": "latest"
14
14
  },
15
15
  "devDependencies": {
16
- "tailwindcss": "^3.4.0",
16
+ "tailwindcss": "^4.0.0",
17
17
  "postcss": "^8.4.0",
18
18
  "autoprefixer": "^10.4.0",
19
19
  "typescript": "^5.0.0",
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -0,0 +1,45 @@
1
+ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
2
+
3
+ export default function DashboardPage() {
4
+ return (
5
+ <main className="container mx-auto p-6">
6
+ <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
7
+
8
+ <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
9
+ <Card>
10
+ <CardHeader>
11
+ <CardTitle>Total Users</CardTitle>
12
+ </CardHeader>
13
+ <CardContent>
14
+ <p className="text-3xl font-bold">1,234</p>
15
+ <p className="text-sm text-muted-foreground mt-2">
16
+ +12% from last month
17
+ </p>
18
+ </CardContent>
19
+ </Card>
20
+
21
+ <Card>
22
+ <CardHeader>
23
+ <CardTitle>Revenue</CardTitle>
24
+ </CardHeader>
25
+ <CardContent>
26
+ <p className="text-3xl font-bold">$45,231</p>
27
+ <p className="text-sm text-muted-foreground mt-2">
28
+ +8% from last month
29
+ </p>
30
+ </CardContent>
31
+ </Card>
32
+
33
+ <Card>
34
+ <CardHeader>
35
+ <CardTitle>Active Sessions</CardTitle>
36
+ </CardHeader>
37
+ <CardContent>
38
+ <p className="text-3xl font-bold">573</p>
39
+ <p className="text-sm text-muted-foreground mt-2">Live now</p>
40
+ </CardContent>
41
+ </Card>
42
+ </div>
43
+ </main>
44
+ );
45
+ }
@@ -0,0 +1,30 @@
1
+ import type React from 'react';
2
+
3
+ export default function DashboardLayout({
4
+ children,
5
+ }: {
6
+ children: React.ReactNode;
7
+ }) {
8
+ return (
9
+ <div className="min-h-screen flex">
10
+ {/* Sidebar placeholder */}
11
+ <aside className="w-64 border-r p-6">
12
+ <h2 className="text-lg font-bold mb-6">Menu</h2>
13
+ <nav className="space-y-2">
14
+ <a href="/dashboard" className="block py-2 hover:underline">
15
+ Dashboard
16
+ </a>
17
+ <a href="/dashboard/users" className="block py-2 hover:underline">
18
+ Users
19
+ </a>
20
+ <a href="/dashboard/settings" className="block py-2 hover:underline">
21
+ Settings
22
+ </a>
23
+ </nav>
24
+ </aside>
25
+
26
+ {/* Main content */}
27
+ <div className="flex-1">{children}</div>
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,16 @@
1
+ import type React from 'react';
2
+ // Public layout - for unauthenticated pages like landing, login, signup
3
+ // Nested layouts allow different shells for different route groups
4
+
5
+ export default function PublicLayout({
6
+ children,
7
+ }: {
8
+ children: React.ReactNode;
9
+ }) {
10
+ return (
11
+ <div className="min-h-screen">
12
+ {/* Public pages don't need the full header/footer */}
13
+ {children}
14
+ </div>
15
+ );
16
+ }
@@ -0,0 +1,33 @@
1
+ export default function LoginPage() {
2
+ return (
3
+ <main className="min-h-screen flex items-center justify-center p-6">
4
+ <div className="w-full max-w-md border rounded-lg p-6">
5
+ <h1 className="text-2xl font-bold mb-6">Sign In</h1>
6
+ <form className="space-y-4">
7
+ <div>
8
+ <label className="block text-sm font-medium mb-2">Email</label>
9
+ <input
10
+ type="email"
11
+ className="w-full px-3 py-2 border rounded-md"
12
+ placeholder="you@example.com"
13
+ />
14
+ </div>
15
+ <div>
16
+ <label className="block text-sm font-medium mb-2">Password</label>
17
+ <input
18
+ type="password"
19
+ className="w-full px-3 py-2 border rounded-md"
20
+ placeholder="••••••••"
21
+ />
22
+ </div>
23
+ <button
24
+ type="submit"
25
+ className="w-full bg-foreground text-background py-2 rounded-md hover:opacity-90"
26
+ >
27
+ Sign In
28
+ </button>
29
+ </form>
30
+ </div>
31
+ </main>
32
+ );
33
+ }