@agility/create-next-app 1.0.0-beta.2

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 (213) hide show
  1. package/.claude/settings.json +7 -0
  2. package/.claude/settings.local.json +24 -0
  3. package/FEATURE_ROADMAP.md +343 -0
  4. package/README.md +205 -0
  5. package/TESTING.md +131 -0
  6. package/bin/create-agility-app.js +48 -0
  7. package/dist/agility/api-keys/generateApiKeys.d.ts +9 -0
  8. package/dist/agility/api-keys/generateApiKeys.d.ts.map +1 -0
  9. package/dist/agility/api-keys/generateApiKeys.js +99 -0
  10. package/dist/agility/api-keys/generateApiKeys.js.map +1 -0
  11. package/dist/agility/api-keys/getApiKeys.d.ts +9 -0
  12. package/dist/agility/api-keys/getApiKeys.d.ts.map +1 -0
  13. package/dist/agility/api-keys/getApiKeys.js +14 -0
  14. package/dist/agility/api-keys/getApiKeys.js.map +1 -0
  15. package/dist/agility/index.d.ts +3 -0
  16. package/dist/agility/index.d.ts.map +1 -0
  17. package/dist/agility/index.js +8 -0
  18. package/dist/agility/index.js.map +1 -0
  19. package/dist/agility/instance/createNewInstance.d.ts +8 -0
  20. package/dist/agility/instance/createNewInstance.d.ts.map +1 -0
  21. package/dist/agility/instance/createNewInstance.js +65 -0
  22. package/dist/agility/instance/createNewInstance.js.map +1 -0
  23. package/dist/agility/instance/getAvailableInstances.d.ts +8 -0
  24. package/dist/agility/instance/getAvailableInstances.d.ts.map +1 -0
  25. package/dist/agility/instance/getAvailableInstances.js +43 -0
  26. package/dist/agility/instance/getAvailableInstances.js.map +1 -0
  27. package/dist/agility/instance/manageInstance.d.ts +9 -0
  28. package/dist/agility/instance/manageInstance.d.ts.map +1 -0
  29. package/dist/agility/instance/manageInstance.js +82 -0
  30. package/dist/agility/instance/manageInstance.js.map +1 -0
  31. package/dist/agility/utils/getMgmtAPIUrl.d.ts +20 -0
  32. package/dist/agility/utils/getMgmtAPIUrl.d.ts.map +1 -0
  33. package/dist/agility/utils/getMgmtAPIUrl.js +61 -0
  34. package/dist/agility/utils/getMgmtAPIUrl.js.map +1 -0
  35. package/dist/auth/api-key/authenticateWithApiKey.d.ts +6 -0
  36. package/dist/auth/api-key/authenticateWithApiKey.d.ts.map +1 -0
  37. package/dist/auth/api-key/authenticateWithApiKey.js +28 -0
  38. package/dist/auth/api-key/authenticateWithApiKey.js.map +1 -0
  39. package/dist/auth/index.d.ts +3 -0
  40. package/dist/auth/index.d.ts.map +1 -0
  41. package/dist/auth/index.js +8 -0
  42. package/dist/auth/index.js.map +1 -0
  43. package/dist/auth/oauth/authenticate.d.ts +6 -0
  44. package/dist/auth/oauth/authenticate.d.ts.map +1 -0
  45. package/dist/auth/oauth/authenticate.js +162 -0
  46. package/dist/auth/oauth/authenticate.js.map +1 -0
  47. package/dist/auth/oauth/constants.d.ts +5 -0
  48. package/dist/auth/oauth/constants.d.ts.map +1 -0
  49. package/dist/auth/oauth/constants.js +9 -0
  50. package/dist/auth/oauth/constants.js.map +1 -0
  51. package/dist/auth/oauth/exchangeCodeForToken.d.ts +7 -0
  52. package/dist/auth/oauth/exchangeCodeForToken.d.ts.map +1 -0
  53. package/dist/auth/oauth/exchangeCodeForToken.js +39 -0
  54. package/dist/auth/oauth/exchangeCodeForToken.js.map +1 -0
  55. package/dist/cli/index.d.ts +3 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +290 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/promptForMissingOptions.d.ts +8 -0
  60. package/dist/cli/promptForMissingOptions.d.ts.map +1 -0
  61. package/dist/cli/promptForMissingOptions.js +92 -0
  62. package/dist/cli/promptForMissingOptions.js.map +1 -0
  63. package/dist/config/env/createEnvFile.d.ts +6 -0
  64. package/dist/config/env/createEnvFile.d.ts.map +1 -0
  65. package/dist/config/env/createEnvFile.js +31 -0
  66. package/dist/config/env/createEnvFile.js.map +1 -0
  67. package/dist/config/index.d.ts +2 -0
  68. package/dist/config/index.d.ts.map +1 -0
  69. package/dist/config/index.js +6 -0
  70. package/dist/config/index.js.map +1 -0
  71. package/dist/config/mcp/createMcpConfig.d.ts +5 -0
  72. package/dist/config/mcp/createMcpConfig.d.ts.map +1 -0
  73. package/dist/config/mcp/createMcpConfig.js +32 -0
  74. package/dist/config/mcp/createMcpConfig.js.map +1 -0
  75. package/dist/config/packages/installAgilityPackages.d.ts +6 -0
  76. package/dist/config/packages/installAgilityPackages.d.ts.map +1 -0
  77. package/dist/config/packages/installAgilityPackages.js +61 -0
  78. package/dist/config/packages/installAgilityPackages.js.map +1 -0
  79. package/dist/config/setupProject.d.ts +8 -0
  80. package/dist/config/setupProject.d.ts.map +1 -0
  81. package/dist/config/setupProject.js +32 -0
  82. package/dist/config/setupProject.js.map +1 -0
  83. package/dist/create-next-app/createNextApp.d.ts +9 -0
  84. package/dist/create-next-app/createNextApp.d.ts.map +1 -0
  85. package/dist/create-next-app/createNextApp.js +83 -0
  86. package/dist/create-next-app/createNextApp.js.map +1 -0
  87. package/dist/create-next-app/index.d.ts +3 -0
  88. package/dist/create-next-app/index.d.ts.map +1 -0
  89. package/dist/create-next-app/index.js +8 -0
  90. package/dist/create-next-app/index.js.map +1 -0
  91. package/dist/scaffold/components/createPageComponents.d.ts +6 -0
  92. package/dist/scaffold/components/createPageComponents.d.ts.map +1 -0
  93. package/dist/scaffold/components/createPageComponents.js +62 -0
  94. package/dist/scaffold/components/createPageComponents.js.map +1 -0
  95. package/dist/scaffold/containers/createContainers.d.ts +6 -0
  96. package/dist/scaffold/containers/createContainers.d.ts.map +1 -0
  97. package/dist/scaffold/containers/createContainers.js +48 -0
  98. package/dist/scaffold/containers/createContainers.js.map +1 -0
  99. package/dist/scaffold/index.d.ts +2 -0
  100. package/dist/scaffold/index.d.ts.map +1 -0
  101. package/dist/scaffold/index.js +6 -0
  102. package/dist/scaffold/index.js.map +1 -0
  103. package/dist/scaffold/instance/createBlankInstance.d.ts +8 -0
  104. package/dist/scaffold/instance/createBlankInstance.d.ts.map +1 -0
  105. package/dist/scaffold/instance/createBlankInstance.js +51 -0
  106. package/dist/scaffold/instance/createBlankInstance.js.map +1 -0
  107. package/dist/scaffold/models/createContentModels.d.ts +6 -0
  108. package/dist/scaffold/models/createContentModels.d.ts.map +1 -0
  109. package/dist/scaffold/models/createContentModels.js +70 -0
  110. package/dist/scaffold/models/createContentModels.js.map +1 -0
  111. package/dist/templates/copyDirectory.d.ts +5 -0
  112. package/dist/templates/copyDirectory.d.ts.map +1 -0
  113. package/dist/templates/copyDirectory.js +28 -0
  114. package/dist/templates/copyDirectory.js.map +1 -0
  115. package/dist/templates/copyTemplates.d.ts +8 -0
  116. package/dist/templates/copyTemplates.d.ts.map +1 -0
  117. package/dist/templates/copyTemplates.js +58 -0
  118. package/dist/templates/copyTemplates.js.map +1 -0
  119. package/dist/templates/index.d.ts +2 -0
  120. package/dist/templates/index.d.ts.map +1 -0
  121. package/dist/templates/index.js +6 -0
  122. package/dist/templates/index.js.map +1 -0
  123. package/dist/types/index.d.ts +50 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/index.js +3 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/dist/utils/git.d.ts +9 -0
  128. package/dist/utils/git.d.ts.map +1 -0
  129. package/dist/utils/git.js +71 -0
  130. package/dist/utils/git.js.map +1 -0
  131. package/dist/utils/validation.d.ts +45 -0
  132. package/dist/utils/validation.d.ts.map +1 -0
  133. package/dist/utils/validation.js +180 -0
  134. package/dist/utils/validation.js.map +1 -0
  135. package/package.json +45 -0
  136. package/src/agility/api-keys/generateApiKeys.ts +100 -0
  137. package/src/agility/api-keys/getApiKeys.ts +13 -0
  138. package/src/agility/index.ts +3 -0
  139. package/src/agility/instance/createNewInstance.ts +67 -0
  140. package/src/agility/instance/getAvailableInstances.ts +49 -0
  141. package/src/agility/instance/manageInstance.ts +90 -0
  142. package/src/agility/utils/getMgmtAPIUrl.ts +68 -0
  143. package/src/auth/api-key/authenticateWithApiKey.ts +24 -0
  144. package/src/auth/index.ts +3 -0
  145. package/src/auth/oauth/authenticate.ts +165 -0
  146. package/src/auth/oauth/constants.ts +6 -0
  147. package/src/auth/oauth/exchangeCodeForToken.ts +43 -0
  148. package/src/cli/index.ts +281 -0
  149. package/src/cli/promptForMissingOptions.ts +104 -0
  150. package/src/config/env/createEnvFile.ts +30 -0
  151. package/src/config/index.ts +2 -0
  152. package/src/config/mcp/createMcpConfig.ts +30 -0
  153. package/src/config/packages/installAgilityPackages.ts +63 -0
  154. package/src/config/setupProject.ts +31 -0
  155. package/src/create-next-app/createNextApp.ts +75 -0
  156. package/src/create-next-app/index.ts +3 -0
  157. package/src/scaffold/components/createPageComponents.ts +74 -0
  158. package/src/scaffold/containers/createContainers.ts +55 -0
  159. package/src/scaffold/index.ts +2 -0
  160. package/src/scaffold/instance/createBlankInstance.ts +55 -0
  161. package/src/scaffold/models/createContentModels.ts +83 -0
  162. package/src/templates/copyDirectory.ts +24 -0
  163. package/src/templates/copyTemplates.ts +57 -0
  164. package/src/templates/index.ts +2 -0
  165. package/src/types/index.ts +55 -0
  166. package/src/utils/git.ts +74 -0
  167. package/src/utils/validation.ts +184 -0
  168. package/templates/.claude/QUICK-START.md +230 -0
  169. package/templates/.claude/README.md +32 -0
  170. package/templates/.claude/settings.json +8 -0
  171. package/templates/BLANK-INSTANCE-SETUP.md +375 -0
  172. package/templates/DEVELOPMENT.md +160 -0
  173. package/templates/EXAMPLE-PROMPTS.md +643 -0
  174. package/templates/PROMPTS.md +410 -0
  175. package/templates/README.md +281 -0
  176. package/templates/agents.md +429 -0
  177. package/templates/app/[locale]/[...slug]/error.tsx +17 -0
  178. package/templates/app/[locale]/[...slug]/not-found.tsx +9 -0
  179. package/templates/app/[locale]/[...slug]/page.tsx +102 -0
  180. package/templates/app/[locale]/layout.tsx +22 -0
  181. package/templates/app/[locale]/page.tsx +12 -0
  182. package/templates/app/api/dynamic-redirect/route.ts +24 -0
  183. package/templates/app/api/preview/exit/route.ts +34 -0
  184. package/templates/app/api/preview/route.ts +63 -0
  185. package/templates/app/api/revalidate/route.ts +118 -0
  186. package/templates/components/agility-components/RichTextArea.tsx +66 -0
  187. package/templates/components/agility-components/index.ts +30 -0
  188. package/templates/components/agility-pages/MainTemplate.tsx +36 -0
  189. package/templates/components/agility-pages/index.ts +11 -0
  190. package/templates/docs/01-agility-cms-overview.md +139 -0
  191. package/templates/docs/02-page-routing.md +251 -0
  192. package/templates/docs/03-creating-components.md +462 -0
  193. package/templates/docs/04-data-fetching.md +484 -0
  194. package/templates/docs/05-containers-and-lists.md +596 -0
  195. package/templates/docs/06-localization.md +561 -0
  196. package/templates/docs/07-caching-strategies.md +410 -0
  197. package/templates/docs/08-common-components.md +756 -0
  198. package/templates/docs/09-whats-included.md +279 -0
  199. package/templates/docs/10-mcp-server-setup.md +153 -0
  200. package/templates/docs/11-linked-nested-content.md +611 -0
  201. package/templates/docs/README.md +164 -0
  202. package/templates/lib/cms/getAgilityContext.ts +28 -0
  203. package/templates/lib/cms/getAgilityPage.ts +51 -0
  204. package/templates/lib/cms/getAgilitySDK.ts +22 -0
  205. package/templates/lib/cms/getContentItem.ts +20 -0
  206. package/templates/lib/cms/getContentList.ts +19 -0
  207. package/templates/lib/cms/getRedirections.ts +85 -0
  208. package/templates/lib/cms/getSitemapFlat.ts +19 -0
  209. package/templates/lib/cms/getSitemapNested.ts +19 -0
  210. package/templates/lib/env.ts +99 -0
  211. package/templates/lib/i18n/config.ts +28 -0
  212. package/templates/proxy.ts +101 -0
  213. package/tsconfig.json +21 -0
@@ -0,0 +1,410 @@
1
+ # Caching Strategies
2
+
3
+ This document explains caching strategies for Agility CMS content in Next.js.
4
+
5
+ ## Overview
6
+
7
+ The project uses Next.js Data Cache with Agility CMS for optimal performance:
8
+ - **Time-based Revalidation**: Content refreshes after a set time
9
+ - **Tag-based Revalidation**: Specific content updates via webhooks
10
+ - **Preview Mode**: Bypass cache for draft content
11
+
12
+ ## Cache Configuration
13
+
14
+ ### Time-based Revalidation
15
+
16
+ Set in page route:
17
+ ```typescript
18
+ // app/[locale]/[...slug]/page.tsx
19
+ export const revalidate = 60 // Revalidate every 60 seconds
20
+ ```
21
+
22
+ Set via environment variable:
23
+ ```env
24
+ AGILITY_PATH_REVALIDATE_DURATION=60
25
+ ```
26
+
27
+ ### How It Works
28
+
29
+ 1. **First Request**: Page generated statically at build time
30
+ 2. **Subsequent Requests**: Cached version served (fast)
31
+ 3. **After 60 seconds**: Next request triggers background regeneration
32
+ 4. **Updated Content**: New version cached for next 60 seconds
33
+
34
+ ## Cache Tags
35
+
36
+ Every piece of content from Agility CMS has a cache tag:
37
+
38
+ ```typescript
39
+ // lib/cms/getContentItem.ts
40
+ agilityClient.config.fetchConfig = {
41
+ next: {
42
+ tags: [`agility-content-${contentID}-${locale}`],
43
+ revalidate: 60,
44
+ },
45
+ };
46
+ ```
47
+
48
+ ### Tag Format
49
+
50
+ - **Content Item**: `agility-content-{contentID}-{locale}`
51
+ - **Content List**: `agility-content-{referenceName}-{locale}`
52
+ - **Sitemap**: `agility-sitemap-flat-{locale}`
53
+ - **Page**: `agility-page-{pageID}-{locale}`
54
+
55
+ ### Why Cache Tags?
56
+
57
+ Cache tags allow targeted revalidation:
58
+ ```typescript
59
+ // Revalidate only blog post 123 in English
60
+ revalidateTag("agility-content-123-en-us");
61
+
62
+ // Revalidate all posts list
63
+ revalidateTag("agility-content-posts-en-us");
64
+ ```
65
+
66
+ ## On-Demand Revalidation
67
+
68
+ ### Webhook Setup
69
+
70
+ 1. Create API route for webhooks:
71
+
72
+ ```typescript
73
+ // app/api/revalidate/route.ts
74
+
75
+ import { revalidateTag } from "next/cache";
76
+ import { NextRequest, NextResponse } from "next/server";
77
+
78
+ export async function POST(request: NextRequest) {
79
+ const body = await request.json();
80
+ const securityKey = request.headers.get("x-agility-security-key");
81
+
82
+ // Verify security key
83
+ if (securityKey !== process.env.AGILITY_SECURITY_KEY) {
84
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
85
+ }
86
+
87
+ const { tag, contentID, locale } = body;
88
+
89
+ try {
90
+ if (tag) {
91
+ // Revalidate specific tag
92
+ revalidateTag(tag);
93
+ } else if (contentID && locale) {
94
+ // Revalidate content by ID
95
+ revalidateTag(`agility-content-${contentID}-${locale}`);
96
+ } else {
97
+ return NextResponse.json({ error: "Missing parameters" }, { status: 400 });
98
+ }
99
+
100
+ return NextResponse.json({ revalidated: true, now: Date.now() });
101
+ } catch (error) {
102
+ return NextResponse.json({ error: "Error revalidating" }, { status: 500 });
103
+ }
104
+ }
105
+ ```
106
+
107
+ 2. Configure webhook in Agility CMS:
108
+ - Go to **Settings > Webhooks**
109
+ - Add webhook URL: `https://yourdomain.com/api/revalidate`
110
+ - Add security header: `x-agility-security-key: your-security-key`
111
+ - Select events: Content Published, Content Unpublished
112
+
113
+ ### Manual Revalidation
114
+
115
+ You can also revalidate programmatically:
116
+
117
+ ```typescript
118
+ import { revalidateTag } from "next/cache";
119
+
120
+ // Revalidate a specific content item
121
+ revalidateTag("agility-content-123-en-us");
122
+
123
+ // Revalidate a content list
124
+ revalidateTag("agility-content-posts-en-us");
125
+
126
+ // Revalidate all pages
127
+ revalidateTag("agility-sitemap-flat-en-us");
128
+ ```
129
+
130
+ ## Preview Mode
131
+
132
+ Preview mode bypasses caching to show draft content.
133
+
134
+ ### Enable Preview
135
+
136
+ ```typescript
137
+ // proxy.ts
138
+ if (request.nextUrl.searchParams.has("agilitypreviewkey")) {
139
+ const agilityPreviewKey = request.nextUrl.searchParams.get("agilitypreviewkey");
140
+ const locale = request.nextUrl.searchParams.get("lang");
141
+ const slug = request.nextUrl.pathname;
142
+
143
+ return NextResponse.redirect(
144
+ `/api/preview?locale=${locale}&slug=${slug}&agilitypreviewkey=${agilityPreviewKey}`
145
+ );
146
+ }
147
+ ```
148
+
149
+ ### Preview API Route
150
+
151
+ ```typescript
152
+ // app/api/preview/route.ts
153
+
154
+ import { cookies } from "next/headers";
155
+ import { NextRequest, NextResponse } from "next/server";
156
+
157
+ export async function GET(request: NextRequest) {
158
+ const searchParams = request.nextUrl.searchParams;
159
+ const agilityPreviewKey = searchParams.get("agilitypreviewkey");
160
+ const locale = searchParams.get("locale");
161
+ const slug = searchParams.get("slug");
162
+
163
+ // Verify preview key
164
+ if (agilityPreviewKey !== process.env.AGILITY_API_PREVIEW_KEY) {
165
+ return NextResponse.json({ error: "Invalid preview key" }, { status: 401 });
166
+ }
167
+
168
+ // Set preview cookie
169
+ (await cookies()).set("agilitypreview", "true", {
170
+ httpOnly: true,
171
+ secure: process.env.NODE_ENV === "production",
172
+ sameSite: "strict",
173
+ maxAge: 60 * 60 * 24, // 24 hours
174
+ });
175
+
176
+ // Redirect to the page
177
+ const redirectUrl = locale === "en-us" ? slug : `/${locale}${slug}`;
178
+ return NextResponse.redirect(new URL(redirectUrl, request.url));
179
+ }
180
+ ```
181
+
182
+ ### Exit Preview
183
+
184
+ ```typescript
185
+ // app/api/preview/exit/route.ts
186
+
187
+ import { cookies } from "next/headers";
188
+ import { NextRequest, NextResponse } from "next/server";
189
+
190
+ export async function GET(request: NextRequest) {
191
+ const searchParams = request.nextUrl.searchParams;
192
+ const locale = searchParams.get("locale");
193
+ const slug = searchParams.get("slug");
194
+
195
+ // Delete preview cookie
196
+ (await cookies()).delete("agilitypreview");
197
+
198
+ // Redirect to the page
199
+ const redirectUrl = locale === "en-us" ? slug : `/${locale}${slug}`;
200
+ return NextResponse.redirect(new URL(redirectUrl, request.url));
201
+ }
202
+ ```
203
+
204
+ ### Using Preview in SDK
205
+
206
+ ```typescript
207
+ // lib/cms/getAgilitySDK.ts
208
+
209
+ import { cookies } from "next/headers";
210
+ import agilitySDK from "@agility/content-fetch";
211
+
212
+ export async function getAgilitySDK({ locale }: { locale: string }) {
213
+ const isPreview = (await cookies()).get("agilitypreview")?.value === "true";
214
+ const apiKey = isPreview
215
+ ? process.env.AGILITY_API_PREVIEW_KEY
216
+ : process.env.AGILITY_API_FETCH_KEY;
217
+
218
+ return agilitySDK.getApi({
219
+ guid: process.env.AGILITY_GUID,
220
+ apiKey,
221
+ isPreview,
222
+ });
223
+ }
224
+ ```
225
+
226
+ ## Cache Strategies
227
+
228
+ ### Strategy 1: High-Frequency Updates
229
+
230
+ For content that changes frequently (e.g., live scores, stock prices):
231
+
232
+ ```typescript
233
+ export const revalidate = 10 // 10 seconds
234
+ ```
235
+
236
+ ### Strategy 2: Moderate Updates
237
+
238
+ For typical websites (e.g., blogs, marketing sites):
239
+
240
+ ```typescript
241
+ export const revalidate = 60 // 1 minute
242
+ ```
243
+
244
+ ### Strategy 3: Infrequent Updates
245
+
246
+ For static content (e.g., documentation, about pages):
247
+
248
+ ```typescript
249
+ export const revalidate = 3600 // 1 hour
250
+ ```
251
+
252
+ ### Strategy 4: On-Demand Only
253
+
254
+ For content that should only update via webhook:
255
+
256
+ ```typescript
257
+ export const revalidate = false // Only revalidate on-demand
258
+ ```
259
+
260
+ ## Cache Debugging
261
+
262
+ ### Check Cache Status
263
+
264
+ Add headers to see cache status:
265
+
266
+ ```typescript
267
+ // proxy.ts
268
+ import { cookies } from "next/headers";
269
+
270
+ export async function proxy(request: NextRequest) {
271
+ const response = NextResponse.next();
272
+
273
+ // Add cache debugging headers
274
+ if (process.env.NODE_ENV === "development") {
275
+ response.headers.set("x-agility-preview", (await cookies()).get("agilitypreview")?.value || "false");
276
+ response.headers.set("x-cache-status", "HIT"); // or MISS, STALE, etc.
277
+ }
278
+
279
+ return response;
280
+ }
281
+ ```
282
+
283
+ ### Log Cache Keys
284
+
285
+ ```typescript
286
+ // lib/cms/getContentItem.ts
287
+ const cacheTag = `agility-content-${contentID}-${locale}`;
288
+ console.log("[Cache] Fetching with tag:", cacheTag);
289
+ ```
290
+
291
+ ## Cache Warming
292
+
293
+ Pre-generate pages at build time:
294
+
295
+ ```typescript
296
+ // app/[locale]/[...slug]/page.tsx
297
+
298
+ export async function generateStaticParams() {
299
+ const allPaths = [];
300
+
301
+ for (const locale of locales) {
302
+ const sitemap = await agilityClient.getSitemapFlat({
303
+ channelName: "website",
304
+ languageCode: locale,
305
+ });
306
+
307
+ const localePaths = Object.values(sitemap)
308
+ .filter((node: any) => !node.redirect && !node.isFolder)
309
+ .map((node: any) => ({
310
+ locale,
311
+ slug: node.path.split("/").slice(1),
312
+ }));
313
+
314
+ allPaths.push(...localePaths);
315
+ }
316
+
317
+ return allPaths;
318
+ }
319
+ ```
320
+
321
+ ## Best Practices
322
+
323
+ 1. **Use Appropriate Revalidation**: Don't over-cache or under-cache
324
+ 2. **Tag Everything**: Always add cache tags to CMS fetches
325
+ 3. **Webhook Integration**: Set up webhooks for instant updates
326
+ 4. **Monitor Performance**: Track cache hit rates
327
+ 5. **Preview Mode**: Use for content editors to see drafts
328
+ 6. **Incremental Updates**: Only revalidate what changed
329
+ 7. **Build-Time Generation**: Pre-render critical pages
330
+
331
+ ## Common Caching Patterns
332
+
333
+ ### Pattern 1: Page-Level Caching
334
+
335
+ ```typescript
336
+ // app/[locale]/[...slug]/page.tsx
337
+ export const revalidate = 60
338
+
339
+ export default async function Page({ params }: PageProps) {
340
+ const agilityData = await getAgilityPage({ params });
341
+ return <div>{/* ... */}</div>;
342
+ }
343
+ ```
344
+
345
+ ### Pattern 2: Component-Level Caching
346
+
347
+ ```typescript
348
+ // components/Header.tsx
349
+ import { unstable_cache } from "next/cache";
350
+ import { getContentItem } from "@/lib/cms/getContentItem";
351
+
352
+ async function getHeaderData(locale: string) {
353
+ return unstable_cache(
354
+ async () => {
355
+ return await getContentItem({
356
+ referenceName: "headerSettings",
357
+ locale,
358
+ });
359
+ },
360
+ ["header-data", locale],
361
+ { revalidate: 300, tags: [`agility-header-${locale}`] }
362
+ )();
363
+ }
364
+
365
+ export default async function Header({ locale }: { locale: string }) {
366
+ const headerData = await getHeaderData(locale);
367
+ return <header>{/* ... */}</header>;
368
+ }
369
+ ```
370
+
371
+ ### Pattern 3: API Route Caching
372
+
373
+ ```typescript
374
+ // app/api/posts/route.ts
375
+ import { NextRequest, NextResponse } from "next/server";
376
+ import { getContentList } from "@/lib/cms/getContentList";
377
+
378
+ export async function GET(request: NextRequest) {
379
+ const locale = request.nextUrl.searchParams.get("locale") || "en-us";
380
+
381
+ const posts = await getContentList({
382
+ referenceName: "posts",
383
+ locale,
384
+ take: 10,
385
+ });
386
+
387
+ return NextResponse.json(posts, {
388
+ headers: {
389
+ "Cache-Control": "s-maxage=60, stale-while-revalidate",
390
+ },
391
+ });
392
+ }
393
+ ```
394
+
395
+ ## Environment-Specific Caching
396
+
397
+ ```typescript
398
+ // lib/cms/getAgilitySDK.ts
399
+
400
+ const revalidate =
401
+ process.env.NODE_ENV === "production"
402
+ ? parseInt(process.env.AGILITY_FETCH_CACHE_DURATION || "60")
403
+ : 0; // No cache in development
404
+ ```
405
+
406
+ ## Next Steps
407
+
408
+ - Read [04-data-fetching.md](./04-data-fetching.md) for data fetching patterns
409
+ - Read [10-deployment.md](./10-deployment.md) for production caching setup
410
+ - Read [11-troubleshooting.md](./11-troubleshooting.md) for cache debugging