create-nextblock 0.11.3 → 0.12.1

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 (51) hide show
  1. package/package.json +1 -1
  2. package/templates/nextblock-template/app/(auth-pages)/sign-up/SignUpForm.tsx +141 -0
  3. package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +40 -122
  4. package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +5 -0
  5. package/templates/nextblock-template/app/[slug]/page.tsx +5 -2
  6. package/templates/nextblock-template/app/[slug]/page.utils.ts +10 -9
  7. package/templates/nextblock-template/app/actions/email.ts +8 -1
  8. package/templates/nextblock-template/app/actions/feedback.ts +1 -0
  9. package/templates/nextblock-template/app/actions/formActions.ts +20 -97
  10. package/templates/nextblock-template/app/actions/interactions.ts +3 -2
  11. package/templates/nextblock-template/app/actions/twoFactorEmail.ts +3 -2
  12. package/templates/nextblock-template/app/actions/visualEditingActions.test.ts +1 -1
  13. package/templates/nextblock-template/app/actions/visualEditingActions.ts +2 -0
  14. package/templates/nextblock-template/app/actions.ts +14 -0
  15. package/templates/nextblock-template/app/api/brand/email-logo/route.ts +48 -0
  16. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +47 -1
  17. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +5169 -8826
  18. package/templates/nextblock-template/app/article/[slug]/page.tsx +5 -2
  19. package/templates/nextblock-template/app/article/[slug]/page.utils.ts +1 -0
  20. package/templates/nextblock-template/app/cms/pages/actions.ts +22 -18
  21. package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +20 -2
  22. package/templates/nextblock-template/app/cms/posts/actions.ts +5 -0
  23. package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +137 -133
  24. package/templates/nextblock-template/app/cms/settings/copyright/actions.ts +36 -0
  25. package/templates/nextblock-template/app/cms/settings/copyright/components/CopyrightForm.tsx +26 -1
  26. package/templates/nextblock-template/app/cms/settings/copyright/page.tsx +6 -2
  27. package/templates/nextblock-template/app/cms/settings/email/actions.ts +7 -3
  28. package/templates/nextblock-template/app/cms/settings/logos/actions.ts +29 -14
  29. package/templates/nextblock-template/app/cms/settings/logos/components/SetActiveLogoButton.tsx +42 -0
  30. package/templates/nextblock-template/app/cms/settings/logos/page.tsx +18 -5
  31. package/templates/nextblock-template/app/layout.tsx +29 -17
  32. package/templates/nextblock-template/app/lib/seo.test.ts +36 -0
  33. package/templates/nextblock-template/app/lib/seo.ts +32 -0
  34. package/templates/nextblock-template/app/product/[slug]/page.tsx +5 -2
  35. package/templates/nextblock-template/components/AppShell.tsx +16 -1
  36. package/templates/nextblock-template/components/auth/AuthBotProtection.tsx +182 -0
  37. package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +36 -42
  38. package/templates/nextblock-template/lib/botProtection/verify.ts +134 -0
  39. package/templates/nextblock-template/lib/email/branding-format.test.ts +133 -0
  40. package/templates/nextblock-template/lib/email/branding-format.ts +123 -0
  41. package/templates/nextblock-template/lib/email/branding.ts +76 -0
  42. package/templates/nextblock-template/lib/logos/active-logo.ts +53 -0
  43. package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +1 -0
  44. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +8 -213
  45. package/templates/nextblock-template/lib/visual-editing/draft-content.ts +4 -2
  46. package/templates/nextblock-template/lib/visual-editing/mutations.ts +2 -2
  47. package/templates/nextblock-template/lib/visual-editing/product-drafts.ts +1 -0
  48. package/templates/nextblock-template/package.json +1 -1
  49. package/templates/nextblock-template/proxy.ts +16 -0
  50. package/templates/nextblock-template/public/images/nextblock-logo-button-tiny.png +0 -0
  51. package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
@@ -117,7 +117,7 @@ async function readPageSnapshot(
117
117
  const client = supabase as any;
118
118
  const { data: page, error: pageError } = await client
119
119
  .from("pages")
120
- .select("id, title, slug, language_id, status, meta_title, meta_description, feature_image_id, version, translation_group_id")
120
+ .select("id, title, slug, language_id, status, meta_title, meta_description, custom_canonical, feature_image_id, version, translation_group_id")
121
121
  .eq("id", pageId)
122
122
  .single();
123
123
 
@@ -144,6 +144,7 @@ async function readPageSnapshot(
144
144
  status: page.status,
145
145
  meta_title: page.meta_title,
146
146
  meta_description: page.meta_description,
147
+ custom_canonical: page.custom_canonical,
147
148
  feature_image_id: page.feature_image_id,
148
149
  translation_group_id: page.translation_group_id,
149
150
  } as Record<string, Json>,
@@ -158,7 +159,7 @@ async function readPostSnapshot(
158
159
  const client = supabase as any;
159
160
  const { data: post, error: postError } = await client
160
161
  .from("posts")
161
- .select("id, title, slug, language_id, status, meta_title, meta_description, label, excerpt, subtitle, published_at, feature_image_id, version, translation_group_id")
162
+ .select("id, title, slug, language_id, status, meta_title, meta_description, custom_canonical, label, excerpt, subtitle, published_at, feature_image_id, version, translation_group_id")
162
163
  .eq("id", postId)
163
164
  .single();
164
165
 
@@ -185,6 +186,7 @@ async function readPostSnapshot(
185
186
  status: post.status,
186
187
  meta_title: post.meta_title,
187
188
  meta_description: post.meta_description,
189
+ custom_canonical: post.custom_canonical,
188
190
  label: post.label,
189
191
  excerpt: post.excerpt,
190
192
  subtitle: post.subtitle,
@@ -94,11 +94,11 @@ export function formatVisualEditingError(error: unknown, fallback: string) {
94
94
  const message = error instanceof Error ? error.message : fallback;
95
95
 
96
96
  if (isMissingDraftStorageError(message, "content_drafts")) {
97
- return "Draft storage is not set up in this database. Apply the content_drafts migration: libs/db/src/supabase/migrations/00000000000014_setup_content_drafts.sql.";
97
+ return "Draft storage is not set up in this database. Apply the schema (npm run db:migrate or the /setup wizard); content_drafts is created by the baseline schema migration.";
98
98
  }
99
99
 
100
100
  if (isMissingDraftStorageError(message, "product_drafts")) {
101
- return "Product draft storage is not set up in this database. Apply the product_drafts migration: libs/db/src/supabase/migrations/00000000000015_setup_product_drafts.sql.";
101
+ return "Product draft storage is not set up in this database. Apply the schema (npm run db:migrate or the /setup wizard); product_drafts is created by the baseline schema migration.";
102
102
  }
103
103
 
104
104
  return message;
@@ -62,6 +62,7 @@ const productSnapshotFields = [
62
62
  "translation_group_id",
63
63
  "meta_title",
64
64
  "meta_description",
65
+ "custom_canonical",
65
66
  "freemius_product_id",
66
67
  "freemius_plan_id",
67
68
  "trial_period_days",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextblock-cms/template",
3
- "version": "0.11.3",
3
+ "version": "0.12.1",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -57,6 +57,12 @@ function isSetupAllowlisted(pathname: string): boolean {
57
57
  pathname.startsWith('/auth/') ||
58
58
  pathname.startsWith('/_next/') ||
59
59
  pathname.startsWith('/favicon') ||
60
+ // Bundled public image assets (the site logo, marketing art). These are referenced by
61
+ // the public chrome AND transactional-email templates, and the Next Image optimizer
62
+ // fetches them server-side WITHOUT an auth cookie — so if the gate bounced them to
63
+ // /setup the optimizer would receive a redirect instead of image bytes and the logo
64
+ // would render broken ("isn't a valid image … received null"). Always serve them.
65
+ pathname.startsWith('/images/') ||
60
66
  // Crawler-facing static routes: keep them reachable while unprovisioned so a fresh
61
67
  // deploy never redirects robots.txt / the sitemap to /setup (which would let crawlers
62
68
  // treat the wizard as the canonical entry point).
@@ -235,6 +241,11 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
235
241
  ];
236
242
  const vercelToolbarConnectSources = ['wss://ws-us3.pusher.com'];
237
243
  const turnstileSources = ['https://challenges.cloudflare.com'];
244
+ // Google reCAPTCHA: api.js is served from www.google.com, the widget worker from
245
+ // www.gstatic.com, and the challenge/badge iframe + verification calls hit
246
+ // www.google.com/recaptcha. Needed by both the bot-protected contact forms and
247
+ // the signup page when the reCAPTCHA provider is selected.
248
+ const recaptchaSources = ['https://www.google.com', 'https://www.gstatic.com'];
238
249
 
239
250
  const developmentHttpSources = isDev
240
251
  ? [
@@ -266,6 +277,7 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
266
277
  'data:',
267
278
  ...vercelSources,
268
279
  ...turnstileSources,
280
+ ...recaptchaSources,
269
281
  ...developmentHttpSources,
270
282
  ]
271
283
  : [
@@ -275,6 +287,7 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
275
287
  ...googleSources,
276
288
  ...vercelSources,
277
289
  ...turnstileSources,
290
+ ...recaptchaSources,
278
291
  ],
279
292
  ),
280
293
  createDirective('script-src-attr', ["'none'"]),
@@ -293,6 +306,7 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
293
306
  'https://checkout.freemius.com',
294
307
  ...googleSources,
295
308
  ...vercelSources,
309
+ ...recaptchaSources,
296
310
  ...developmentHttpSources,
297
311
  ]),
298
312
  createDirective('font-src', [
@@ -310,6 +324,7 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
310
324
  ...vercelSources,
311
325
  ...vercelToolbarConnectSources,
312
326
  ...turnstileSources,
327
+ ...recaptchaSources,
313
328
  ...developmentConnectSources,
314
329
  ]),
315
330
  createDirective('frame-src', [
@@ -323,6 +338,7 @@ function createContentSecurityPolicy(nonceValue: string, supabaseUrl: string | u
323
338
  'https://vercel.live',
324
339
  'https://vercel.com',
325
340
  ...turnstileSources,
341
+ ...recaptchaSources,
326
342
  ]),
327
343
  createDirective('media-src', ["'self'", 'data:', 'blob:', supabaseOrigin, ...assetSources]),
328
344
  createDirective('worker-src', ["'self'", 'blob:']),