@timbenniks/contentstack-platform-app-scaffold 0.1.0 → 0.1.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 (36) hide show
  1. package/README.md +141 -0
  2. package/dist/commands/scaffold.d.ts +0 -1
  3. package/dist/commands/scaffold.d.ts.map +1 -1
  4. package/dist/commands/scaffold.js +0 -5
  5. package/dist/commands/scaffold.js.map +1 -1
  6. package/dist/services/prompts.d.ts.map +1 -1
  7. package/dist/services/prompts.js +94 -7
  8. package/dist/services/prompts.js.map +1 -1
  9. package/dist/services/scaffold.d.ts.map +1 -1
  10. package/dist/services/scaffold.js +68 -19
  11. package/dist/services/scaffold.js.map +1 -1
  12. package/dist/types.d.ts +0 -3
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/types.js.map +1 -1
  15. package/oclif.manifest.json +5 -21
  16. package/package.json +6 -2
  17. package/templates/nextjs/.env.example.hbs +31 -4
  18. package/templates/nextjs/app/api/auth/[...nextauth]/route.ts.hbs +1 -0
  19. package/templates/nextjs/app/api/brandkit/[...path]/route.ts.hbs +7 -18
  20. package/templates/nextjs/app/api/cma/[...path]/route.ts.hbs +7 -18
  21. package/templates/nextjs/app/api/launch/[...path]/route.ts.hbs +7 -18
  22. package/templates/nextjs/app/assets/page.tsx.hbs +27 -12
  23. package/templates/nextjs/app/brandkit/page.tsx.hbs +32 -19
  24. package/templates/nextjs/app/entries/page.tsx.hbs +29 -13
  25. package/templates/nextjs/app/globals.css.hbs +175 -0
  26. package/templates/nextjs/app/launch/page.tsx.hbs +32 -19
  27. package/templates/nextjs/app/layout.tsx.hbs +19 -4
  28. package/templates/nextjs/app/page.tsx.hbs +142 -38
  29. package/templates/nextjs/app/providers.tsx.hbs +13 -1
  30. package/templates/nextjs/lib/auth.ts.hbs +48 -10
  31. package/templates/nextjs/manifest.json +3 -4
  32. package/templates/nextjs/next.config.ts +7 -0
  33. package/templates/nextjs/types/next-auth.d.ts.hbs +8 -0
  34. package/templates/nextjs/next.config.js +0 -4
  35. package/templates/nextjs/package.json.hbs +0 -24
  36. package/templates/nextjs/tsconfig.json +0 -21
@@ -1,55 +1,159 @@
1
1
  {{#if features.oauth}}
2
- import { auth } from "@/lib/auth"
3
- {{/if}}
2
+ import { auth, signIn, signOut } from "@/lib/auth"
3
+ import { Button } from "@/components/ui/button"
4
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
5
+
6
+ export const dynamic = "force-dynamic"
4
7
 
5
- export default {{#if features.oauth}}async {{/if}}function Home() {
6
- {{#if features.oauth}}
8
+ export default async function Home() {
7
9
  const session = await auth()
8
- {{/if}}
10
+
11
+ if (session) {
12
+ return (
13
+ <main className="min-h-screen p-8 max-w-2xl mx-auto">
14
+ <h1 className="text-3xl font-bold mb-2">
15
+ Welcome, {(session.user as { name?: string })?.name ?? "User"}
16
+ </h1>
17
+ <p className="text-muted-foreground mb-8">You are signed in with Contentstack.</p>
18
+
19
+ <div className="grid gap-4">
20
+ {{#if features.cma}}
21
+ <Card>
22
+ <CardHeader>
23
+ <CardTitle>Content Management</CardTitle>
24
+ <CardDescription>Manage your entries and assets</CardDescription>
25
+ </CardHeader>
26
+ <CardContent className="flex gap-2">
27
+ <Button variant="secondary" asChild><a href="/entries">Entries</a></Button>
28
+ <Button variant="secondary" asChild><a href="/assets">Assets</a></Button>
29
+ </CardContent>
30
+ </Card>
31
+ {{/if}}
32
+ {{#if features.launch}}
33
+ <Card>
34
+ <CardHeader>
35
+ <CardTitle>Launch</CardTitle>
36
+ <CardDescription>Manage your deployment projects</CardDescription>
37
+ </CardHeader>
38
+ <CardContent>
39
+ <Button variant="secondary" asChild><a href="/launch">Projects</a></Button>
40
+ </CardContent>
41
+ </Card>
42
+ {{/if}}
43
+ {{#if features.brandkit}}
44
+ <Card>
45
+ <CardHeader>
46
+ <CardTitle>Brand Kit AI</CardTitle>
47
+ <CardDescription>Manage your brand kits and voice profiles</CardDescription>
48
+ </CardHeader>
49
+ <CardContent>
50
+ <Button variant="secondary" asChild><a href="/brandkit">Brand Kits</a></Button>
51
+ </CardContent>
52
+ </Card>
53
+ {{/if}}
54
+ </div>
55
+
56
+ <form
57
+ className="mt-8"
58
+ action={async () => {
59
+ "use server"
60
+ await signOut({ redirectTo: "/" })
61
+ }}
62
+ >
63
+ <Button variant="outline" type="submit">Sign Out</Button>
64
+ </form>
65
+ </main>
66
+ )
67
+ }
9
68
 
10
69
  return (
11
- <main style=\{{ padding: "2rem", fontFamily: "system-ui, sans-serif" }}>
12
- <h1>{{projectName}}</h1>
13
- <p>Region: <code>{{region}}</code></p>
14
- <p>Built with <a href="https://github.com/contentstack/platform-sdk">Contentstack Platform SDK</a></p>
15
-
16
- <h2>Getting Started</h2>
17
- <ol>
18
- <li>Copy <code>.env.example</code> to <code>.env.local</code></li>
19
- <li>Fill in your Contentstack credentials</li>
20
- <li>Start building!</li>
21
- </ol>
22
- {{#if features.oauth}}
23
-
24
- <h2>Authentication</h2>
25
- {session ? (
26
- <p>Signed in. <a href="/api/auth/signout">Sign out</a></p>
27
- ) : (
28
- <p><a href="/api/auth/signin">Sign in with Contentstack</a></p>
29
- )}
30
- {{/if}}
70
+ <main className="min-h-screen flex items-center justify-center p-8">
71
+ <Card className="w-full max-w-md">
72
+ <CardHeader>
73
+ <CardTitle className="text-2xl">{{projectName}}</CardTitle>
74
+ <CardDescription>
75
+ Region: <code className="text-xs bg-muted px-1 py-0.5 rounded">{{region}}</code>
76
+ </CardDescription>
77
+ </CardHeader>
78
+ <CardContent className="space-y-4">
79
+ <ol className="list-decimal list-inside text-sm text-muted-foreground space-y-1">
80
+ <li>Copy <code className="text-xs bg-muted px-1 py-0.5 rounded">.env.example</code> to <code className="text-xs bg-muted px-1 py-0.5 rounded">.env.local</code></li>
81
+ <li>Fill in your Contentstack credentials</li>
82
+ <li>Start building!</li>
83
+ </ol>
84
+ <form
85
+ action={async () => {
86
+ "use server"
87
+ await signIn("contentstack", { redirectTo: "/" })
88
+ }}
89
+ >
90
+ <Button className="w-full" type="submit">Sign in with Contentstack</Button>
91
+ </form>
92
+ </CardContent>
93
+ </Card>
94
+ </main>
95
+ )
96
+ }
97
+ {{else}}
98
+ import { Button } from "@/components/ui/button"
99
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
100
+
101
+ export default function Home() {
102
+ return (
103
+ <main className="min-h-screen p-8 max-w-2xl mx-auto">
104
+ <h1 className="text-3xl font-bold mb-2">{{projectName}}</h1>
105
+ <p className="text-muted-foreground mb-8">
106
+ Region: <code className="text-xs bg-muted px-1 py-0.5 rounded">{{region}}</code>
107
+ </p>
108
+
109
+ <Card className="mb-6">
110
+ <CardHeader>
111
+ <CardTitle>Getting Started</CardTitle>
112
+ <CardDescription>Set up your Contentstack credentials to begin</CardDescription>
113
+ </CardHeader>
114
+ <CardContent>
115
+ <ol className="list-decimal list-inside text-sm text-muted-foreground space-y-1">
116
+ <li>Copy <code className="text-xs bg-muted px-1 py-0.5 rounded">.env.example</code> to <code className="text-xs bg-muted px-1 py-0.5 rounded">.env.local</code></li>
117
+ <li>Fill in your Contentstack credentials</li>
118
+ <li>Start building!</li>
119
+ </ol>
120
+ </CardContent>
121
+ </Card>
31
122
  {{#if features.cma}}
32
123
 
33
- <h2>Content Management</h2>
34
- <ul>
35
- <li><a href="/entries">Entries</a></li>
36
- <li><a href="/assets">Assets</a></li>
37
- </ul>
124
+ <Card className="mb-4">
125
+ <CardHeader>
126
+ <CardTitle>Content Management</CardTitle>
127
+ </CardHeader>
128
+ <CardContent className="flex gap-2">
129
+ <Button variant="secondary" asChild><a href="/entries">Entries</a></Button>
130
+ <Button variant="secondary" asChild><a href="/assets">Assets</a></Button>
131
+ </CardContent>
132
+ </Card>
38
133
  {{/if}}
39
134
  {{#if features.launch}}
40
135
 
41
- <h2>Launch</h2>
42
- <ul>
43
- <li><a href="/launch">Projects</a></li>
44
- </ul>
136
+ <Card className="mb-4">
137
+ <CardHeader>
138
+ <CardTitle>Launch</CardTitle>
139
+ </CardHeader>
140
+ <CardContent>
141
+ <Button variant="secondary" asChild><a href="/launch">Projects</a></Button>
142
+ </CardContent>
143
+ </Card>
45
144
  {{/if}}
46
145
  {{#if features.brandkit}}
47
146
 
48
- <h2>Brand Kit AI</h2>
49
- <ul>
50
- <li><a href="/brandkit">Brand Kits</a></li>
51
- </ul>
147
+ <Card className="mb-4">
148
+ <CardHeader>
149
+ <CardTitle>Brand Kit AI</CardTitle>
150
+ </CardHeader>
151
+ <CardContent>
152
+ <Button variant="secondary" asChild><a href="/brandkit">Brand Kits</a></Button>
153
+ </CardContent>
154
+ </Card>
52
155
  {{/if}}
53
156
  </main>
54
157
  )
55
158
  }
159
+ {{/if}}
@@ -4,7 +4,19 @@ import { ContentstackProvider } from "@timbenniks/contentstack-platform-sdk/reac
4
4
 
5
5
  export function Providers({ children }: { children: React.ReactNode }) {
6
6
  return (
7
- <ContentstackProvider region="{{region}}">
7
+ <ContentstackProvider
8
+ region={process.env.NEXT_PUBLIC_CONTENTSTACK_REGION as "{{region}}" ?? "{{region}}"}
9
+ apiKey={process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY ?? ""}
10
+ proxyBasePath="/api/cma"
11
+ {{#if features.launch}}
12
+ organizationUid={process.env.NEXT_PUBLIC_CONTENTSTACK_ORGANIZATION_UID ?? ""}
13
+ {{else if features.brandkit}}
14
+ organizationUid={process.env.NEXT_PUBLIC_CONTENTSTACK_ORGANIZATION_UID ?? ""}
15
+ {{/if}}
16
+ {{#if features.brandkit}}
17
+ brandKitUid={process.env.NEXT_PUBLIC_CONTENTSTACK_BRAND_KIT_UID ?? ""}
18
+ {{/if}}
19
+ >
8
20
  {children}
9
21
  </ContentstackProvider>
10
22
  )
@@ -1,12 +1,50 @@
1
- import { createContentstackAuth } from "@timbenniks/contentstack-platform-sdk/server/middleware"
2
1
  import type { ContentstackRegion } from "@timbenniks/contentstack-platform-sdk/regions"
2
+ import { createContentstackAuth } from "@timbenniks/contentstack-platform-sdk/server/middleware"
3
+ import type { NextRequest } from "next/server"
4
+
5
+ type AuthConfig = Awaited<ReturnType<typeof createContentstackAuth>>
6
+
7
+ let _authConfig: AuthConfig | null = null
8
+
9
+ async function getAuthConfig(): Promise<AuthConfig> {
10
+ if (!_authConfig) {
11
+ _authConfig = await createContentstackAuth({
12
+ region: (process.env.CONTENTSTACK_REGION ?? "{{region}}") as ContentstackRegion,
13
+ appId: process.env.CONTENTSTACK_APP_ID!,
14
+ clientId: process.env.CONTENTSTACK_CLIENT_ID!,
15
+ clientSecret: process.env.CONTENTSTACK_CLIENT_SECRET!,
16
+ secret: process.env.AUTH_SECRET!,
17
+ scopes: [{{#each scopes}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}}],
18
+ trustHost: true,
19
+ signInPage: "/",
20
+ errorPage: "/",
21
+ })
22
+ }
23
+ return _authConfig
24
+ }
25
+
26
+ export const handlers = {
27
+ GET: async (req: NextRequest) => {
28
+ const config = await getAuthConfig()
29
+ return config.handlers.GET(req)
30
+ },
31
+ POST: async (req: NextRequest) => {
32
+ const config = await getAuthConfig()
33
+ return config.handlers.POST(req)
34
+ },
35
+ }
36
+
37
+ export async function auth() {
38
+ const config = await getAuthConfig()
39
+ return config.auth()
40
+ }
41
+
42
+ export async function signIn(provider?: string, options?: Record<string, unknown>) {
43
+ const config = await getAuthConfig()
44
+ return config.signIn(provider, options)
45
+ }
3
46
 
4
- export const { handlers, auth } = await createContentstackAuth({
5
- region: (process.env.CONTENTSTACK_REGION ?? "{{region}}") as ContentstackRegion,
6
- appId: process.env.CONTENTSTACK_APP_ID!,
7
- clientId: process.env.CONTENTSTACK_CLIENT_ID!,
8
- clientSecret: process.env.CONTENTSTACK_CLIENT_SECRET!,
9
- secret: process.env.AUTH_SECRET!,
10
- scopes: [{{#each scopes}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}}],
11
- trustHost: true,
12
- })
47
+ export async function signOut(options?: Record<string, unknown>) {
48
+ const config = await getAuthConfig()
49
+ return config.signOut(options)
50
+ }
@@ -1,10 +1,9 @@
1
1
  [
2
- { "path": "package.json" },
3
2
  { "path": ".env.example" },
4
- { "path": ".gitignore" },
5
- { "path": "tsconfig.json" },
6
- { "path": "next.config.js" },
3
+ { "path": "next.config.ts" },
4
+ { "path": "types/next-auth.d.ts", "requiredFeatures": ["oauth"] },
7
5
  { "path": "lib/auth.ts", "requiredFeatures": ["oauth"] },
6
+ { "path": "app/globals.css" },
8
7
  { "path": "app/layout.tsx" },
9
8
  { "path": "app/page.tsx" },
10
9
  { "path": "app/providers.tsx", "anyFeatures": ["cma", "launch", "brandkit"] },
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from "next"
2
+
3
+ const nextConfig: NextConfig = {
4
+ transpilePackages: ["@timbenniks/contentstack-platform-sdk"],
5
+ }
6
+
7
+ export default nextConfig
@@ -0,0 +1,8 @@
1
+ import "next-auth"
2
+
3
+ declare module "next-auth" {
4
+ interface Session {
5
+ accessToken?: string
6
+ error?: "RefreshAccessTokenError"
7
+ }
8
+ }
@@ -1,4 +0,0 @@
1
- /** @type {import('next').NextConfig} */
2
- const nextConfig = {}
3
-
4
- module.exports = nextConfig
@@ -1,24 +0,0 @@
1
- {
2
- "name": "{{projectName}}",
3
- "version": "0.1.0",
4
- "private": true,
5
- "scripts": {
6
- "dev": "next dev",
7
- "build": "next build",
8
- "start": "next start",
9
- "lint": "next lint"
10
- },
11
- "dependencies": {
12
- "next": "^15.0.0",
13
- "react": "^19.0.0",
14
- "react-dom": "^19.0.0",
15
- "@timbenniks/contentstack-platform-sdk": "^{{sdkVersion}}"{{#if features.oauth}},
16
- "next-auth": "5.0.0-beta.30"{{/if}}
17
- },
18
- "devDependencies": {
19
- "typescript": "^5.5.0",
20
- "@types/react": "^19.0.0",
21
- "@types/react-dom": "^19.0.0",
22
- "@types/node": "^22.0.0"
23
- }
24
- }
@@ -1,21 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2017",
4
- "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": true,
6
- "skipLibCheck": true,
7
- "strict": true,
8
- "noEmit": true,
9
- "esModuleInterop": true,
10
- "module": "esnext",
11
- "moduleResolution": "bundler",
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "jsx": "preserve",
15
- "incremental": true,
16
- "plugins": [{ "name": "next" }],
17
- "paths": { "@/*": ["./*"] }
18
- },
19
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
20
- "exclude": ["node_modules"]
21
- }