bsmnt 0.14.0 → 0.15.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.
Files changed (116) hide show
  1. package/dist/core/create/internal-ids.d.ts +1 -0
  2. package/dist/core/create/internal-ids.d.ts.map +1 -1
  3. package/dist/core/create/internal-ids.js +1 -0
  4. package/dist/core/create/internal-ids.js.map +1 -1
  5. package/dist/domain/skills.d.ts +5 -0
  6. package/dist/domain/skills.d.ts.map +1 -1
  7. package/dist/domain/skills.js +9 -1
  8. package/dist/domain/skills.js.map +1 -1
  9. package/dist/infrastructure/create/format-project.d.ts +9 -0
  10. package/dist/infrastructure/create/format-project.d.ts.map +1 -0
  11. package/dist/infrastructure/create/format-project.js +21 -0
  12. package/dist/infrastructure/create/format-project.js.map +1 -0
  13. package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
  14. package/dist/infrastructure/create/lifecycle-registry.js +5 -0
  15. package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
  16. package/dist/modules/features/cms/sanity-pagebuilder/index.d.ts.map +1 -1
  17. package/dist/modules/features/cms/sanity-pagebuilder/index.js +1 -0
  18. package/dist/modules/features/cms/sanity-pagebuilder/index.js.map +1 -1
  19. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.d.ts.map +1 -1
  20. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js +1 -0
  21. package/dist/modules/features/cms/sanity-pagebuilder-cache/index.js.map +1 -1
  22. package/package.json +1 -1
  23. package/src/agent-skills/launch-ready/SKILL.md +114 -0
  24. package/src/agent-skills/launch-ready/references/a11y.md +74 -0
  25. package/src/agent-skills/launch-ready/references/content.md +65 -0
  26. package/src/agent-skills/launch-ready/references/crawlers.md +89 -0
  27. package/src/agent-skills/launch-ready/references/launch.md +44 -0
  28. package/src/agent-skills/launch-ready/references/metadata.md +83 -0
  29. package/src/agent-skills/launch-ready/references/performance.md +36 -0
  30. package/src/agent-skills/launch-ready/references/routing.md +47 -0
  31. package/src/agent-skills/launch-ready/references/security.md +39 -0
  32. package/src/modules/features/cms/sanity/files/app/layout.tsx +2 -2
  33. package/src/modules/features/cms/sanity/files/lib/utils/metadata.ts +2 -2
  34. package/src/modules/features/cms/sanity/files/lib/utils/url.ts +6 -3
  35. package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +3 -1
  36. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/redirect-import-dialog.tsx +538 -0
  37. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/csv.ts +88 -0
  38. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +22 -0
  39. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +15 -0
  40. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +20 -0
  41. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/redirect-import.ts +651 -0
  42. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +2 -0
  43. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
  44. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
  45. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/metadata.ts +60 -6
  46. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +22 -1
  47. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
  48. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/structure.ts +16 -1
  49. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/tags.ts +5 -2
  50. package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +8 -11
  51. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/metadata.ts +109 -136
  52. package/src/modules/features/cms/sanity-pagebuilder-cache/files/components/sanity/rich-text.tsx +3 -1
  53. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/components/redirect-import-dialog.tsx +538 -0
  54. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/csv.ts +88 -0
  55. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/fetchers/breadcrumbs.ts +25 -0
  56. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/page-builder-config.ts +15 -0
  57. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/queries.ts +20 -0
  58. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/redirect-import.ts +651 -0
  59. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/sanity.config.ts +2 -0
  60. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/redirect.ts +9 -6
  61. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/layout/structured-data.ts +8 -0
  62. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/metadata.ts +60 -6
  63. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/page.ts +22 -1
  64. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/schemas/shared/richText.ts +0 -1
  65. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/structure.ts +16 -1
  66. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/integrations/sanity/tags.ts +6 -2
  67. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/scripts/sanity-typegen.ts +8 -11
  68. package/src/modules/features/cms/sanity-pagebuilder-cache/files/lib/utils/metadata.ts +109 -136
  69. package/src/templates/next-default/.env.example +3 -1
  70. package/src/templates/next-default/app/layout.tsx +2 -1
  71. package/src/templates/next-default/app/robots.ts +9 -3
  72. package/src/templates/next-default/lib/utils/metadata.ts +2 -1
  73. package/src/templates/next-default/lib/utils/url.ts +20 -3
  74. package/src/templates/next-default/next.config.ts +16 -0
  75. package/src/templates/next-experiments/.env.example +3 -1
  76. package/src/templates/next-experiments/app/layout.tsx +2 -1
  77. package/src/templates/next-experiments/app/robots.ts +9 -3
  78. package/src/templates/next-experiments/lib/utils/metadata.ts +2 -1
  79. package/src/templates/next-experiments/lib/utils/url.ts +20 -3
  80. package/src/templates/next-experiments/next.config.ts +16 -0
  81. package/src/templates/next-pagebuilder/.env.example +3 -1
  82. package/src/templates/next-pagebuilder/.github/workflows/ci.yml +32 -8
  83. package/src/templates/next-pagebuilder/AGENTS.md +3 -0
  84. package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +45 -7
  85. package/src/templates/next-pagebuilder/app/layout.tsx +3 -41
  86. package/src/templates/next-pagebuilder/app/robots.ts +9 -3
  87. package/src/templates/next-pagebuilder/biome.json +2 -1
  88. package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +1 -1
  89. package/src/templates/next-pagebuilder/components/page-document/index.tsx +27 -35
  90. package/src/templates/next-pagebuilder/lefthook.yml +1 -1
  91. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +32 -29
  92. package/src/templates/next-pagebuilder/lib/utils/base-url.ts +18 -3
  93. package/src/templates/next-pagebuilder/lib/utils/breadcrumbs.ts +70 -0
  94. package/src/templates/next-pagebuilder/next.config.ts +16 -0
  95. package/src/templates/next-pagebuilder/package.json +1 -1
  96. package/src/templates/next-pagebuilder-cache/.env.example +3 -1
  97. package/src/templates/next-pagebuilder-cache/.github/workflows/ci.yml +32 -8
  98. package/src/templates/next-pagebuilder-cache/AGENTS.md +3 -0
  99. package/src/templates/next-pagebuilder-cache/app/(content)/[[...slug]]/page.tsx +46 -7
  100. package/src/templates/next-pagebuilder-cache/app/layout.tsx +5 -46
  101. package/src/templates/next-pagebuilder-cache/app/robots.ts +9 -3
  102. package/src/templates/next-pagebuilder-cache/biome.json +2 -1
  103. package/src/templates/next-pagebuilder-cache/components/layout/footer/index.tsx +1 -1
  104. package/src/templates/next-pagebuilder-cache/components/page-document/index.tsx +27 -35
  105. package/src/templates/next-pagebuilder-cache/lefthook.yml +1 -1
  106. package/src/templates/next-pagebuilder-cache/lib/integrations/sanity/sanity.types.ts +32 -29
  107. package/src/templates/next-pagebuilder-cache/lib/utils/base-url.ts +18 -3
  108. package/src/templates/next-pagebuilder-cache/lib/utils/breadcrumbs.ts +70 -0
  109. package/src/templates/next-pagebuilder-cache/next.config.ts +16 -0
  110. package/src/templates/next-pagebuilder-cache/package.json +1 -1
  111. package/src/templates/next-webgl/.env.example +3 -1
  112. package/src/templates/next-webgl/app/layout.tsx +2 -1
  113. package/src/templates/next-webgl/app/robots.ts +9 -3
  114. package/src/templates/next-webgl/lib/utils/metadata.ts +2 -1
  115. package/src/templates/next-webgl/lib/utils/url.ts +20 -3
  116. package/src/templates/next-webgl/next.config.ts +16 -0
@@ -0,0 +1,44 @@
1
+ # On the real domain
2
+
3
+ These only fail in production, so check them against the deployed URL.
4
+
5
+ ## LAUNCH-01 · Forms deliver on production
6
+
7
+ **Must not ship** · only if the site has forms
8
+
9
+ Submit each form on production and confirm the submission arrives. The usual
10
+ failure: the form's API key is set for Preview but not for Production, so the
11
+ form works on every preview and silently drops submissions after launch.
12
+
13
+ ## LAUNCH-02 · CMS publishing updates production
14
+
15
+ **Must not ship** · only if the site uses a CMS
16
+
17
+ Publish a small change in the CMS and confirm production shows it. The
18
+ revalidation webhook points at the production URL and carries its secret.
19
+
20
+ ## LAUNCH-03 · One host
21
+
22
+ **Fix before launch**
23
+
24
+ Pick the apex domain or `www`. In Vercel's domain settings, the other
25
+ redirects to it permanently.
26
+
27
+ **Check:**
28
+
29
+ ```bash
30
+ curl -sI https://<other-host>/ | grep -i '^location'
31
+ ```
32
+
33
+ It points at the chosen host.
34
+
35
+ ## LAUNCH-04 · Old URLs redirect on a relaunch
36
+
37
+ **Fix before launch** · only if *Replaces an existing site: yes*
38
+
39
+ Every old URL with traffic or backlinks redirects to its new equivalent
40
+ through `redirects()` in `next.config.ts`. Ask the user for the old site's URL
41
+ list: its sitemap, or its top pages in analytics.
42
+
43
+ **Check:** request a sample of old URLs. Each returns `308` to a page that
44
+ returns `200`.
@@ -0,0 +1,83 @@
1
+ # Metadata
2
+
3
+ ## META-01 · Every page has a real title
4
+
5
+ **Must not ship**
6
+
7
+ Each route exports `metadata` or `generateMetadata` with its own title. If
8
+ `app/layout.tsx` still has the `"Basement Starter"` default and its
9
+ `"%s - Basement Starter"` template, replace both with the site's name.
10
+
11
+ **Check:**
12
+
13
+ ```bash
14
+ curl -s localhost:3000/<route> | grep -o '<title>[^<]*'
15
+ ```
16
+
17
+ ## META-02 · Metadata is in the server HTML
18
+
19
+ **Must not ship**
20
+
21
+ Set titles, descriptions and share tags through the Metadata API, never with
22
+ `document.title` or a client effect. Crawlers and link previews don't run
23
+ JavaScript.
24
+
25
+ **Check:** the tags appear in `curl -s localhost:3000/<route>`, not only in
26
+ the browser's DOM.
27
+
28
+ ## META-03 · The share image loads
29
+
30
+ **Must not ship**
31
+
32
+ A declared `og:image` is absolute and returns an image.
33
+
34
+ If the layout or `generatePageMetadata` defaults to `/opengraph-image.jpg`,
35
+ add that file: no template ships it. Until `public/opengraph-image.jpg`
36
+ exists, every share card is broken, and so is the Organization JSON-LD logo,
37
+ which uses the same path.
38
+
39
+ **Check:**
40
+
41
+ ```bash
42
+ img=$(curl -s localhost:3000/ | grep -o 'property="og:image" content="[^"]*' | cut -d'"' -f4)
43
+ curl -so /dev/null -w '%{http_code} %{content_type}\n' "$img"
44
+ ```
45
+
46
+ Expect `200 image/...`.
47
+
48
+ ## META-04 · No `localhost` URLs in production
49
+
50
+ **Must not ship**
51
+
52
+ `metadataBase`, canonicals and share URLs read `NEXT_PUBLIC_BASE_URL`, then
53
+ the Vercel deployment URL, and fall back to `http://localhost:3000` off Vercel.
54
+ Set it for the Production environment.
55
+
56
+ **Check:**
57
+
58
+ ```bash
59
+ curl -s https://<production>/ | grep -c 'localhost:3000'
60
+ ```
61
+
62
+ Expect `0`.
63
+
64
+ ## META-05 · Titles are unique
65
+
66
+ **Fix before launch**
67
+
68
+ Distinct pages have distinct titles. Variants that canonicalize to one page
69
+ are exempt.
70
+
71
+ ## META-06 · Public pages have a description
72
+
73
+ **Fix before launch**
74
+
75
+ Slack, LinkedIn and iMessage show the description as the preview text. If the
76
+ layout's default reads `package.json`'s `description`, write a real one there.
77
+
78
+ ## META-07 · `<html lang>` matches the content
79
+
80
+ **Fix before launch**
81
+
82
+ The starter sets `lang="en"`. Change it when the site isn't English, and set
83
+ it per locale on a multilingual site.
@@ -0,0 +1,36 @@
1
+ # Performance
2
+
3
+ ## PERF-01 · The LCP image isn't lazy
4
+
5
+ **Fix before launch**
6
+
7
+ The largest image in the first screen (usually the hero) passes `priority` to
8
+ `@/components/ui/image`. Everything below the fold stays lazy, which is the
9
+ default.
10
+
11
+ ## PERF-02 · Image `sizes` match the layout
12
+
13
+ **Fix before launch**
14
+
15
+ `sizes` describes the width the image renders at. Without it, the image
16
+ component falls back to `100vw` and the browser downloads the largest
17
+ variant, which is only right for full-width images. Build `sizes` with
18
+ `buildImageSizes` or `buildGridImageSizes` from `lib/utils/image-sizes.ts`.
19
+
20
+ The `no-fill-without-sizes` lint rule catches `fill` with no `sizes`. It can't
21
+ tell whether the value is correct.
22
+
23
+ ## PERF-03 · Responses are compressed
24
+
25
+ **Fix before launch** · only when hosted outside Vercel
26
+
27
+ Vercel compresses responses by default. Another host has to serve HTML, JS
28
+ and CSS with gzip or brotli.
29
+
30
+ **Check:**
31
+
32
+ ```bash
33
+ curl -sI -H 'Accept-Encoding: gzip, br' https://<production>/ | grep -i content-encoding
34
+ ```
35
+
36
+ Expect `gzip` or `br`.
@@ -0,0 +1,47 @@
1
+ # Routing
2
+
3
+ ## ROUTE-01 · Missing pages return 404
4
+
5
+ **Must not ship**
6
+
7
+ When a dynamic or CMS route has no data, call `notFound()` before any
8
+ `<Suspense>`. Once a response starts streaming, its status is already 200.
9
+ Next can't change it then, and injects a `noindex` tag instead.
10
+
11
+ ```tsx
12
+ export default async function Page({ params }: PageProps<"/blog/[slug]">) {
13
+ const { slug } = await params
14
+ const post = await getPost(slug)
15
+ if (!post) notFound()
16
+ return <Post post={post} />
17
+ }
18
+ ```
19
+
20
+ **Check:**
21
+
22
+ ```bash
23
+ curl -so /dev/null -w '%{http_code}\n' localhost:3000/does-not-exist
24
+ ```
25
+
26
+ Expect `404`. Repeat under each dynamic segment, such as `/blog/does-not-exist`.
27
+
28
+ **Not this:** redirecting unknown paths to `/`. That's still a missing page
29
+ answering 200.
30
+
31
+ ## ROUTE-02 · No internal link is broken
32
+
33
+ **Must not ship**
34
+
35
+ Every internal link resolves to a page that returns 200. A control that only
36
+ runs JavaScript is a `<button>`, not `<a href="#">`. An `#id` that exists on the
37
+ page, or a "back to top" link, is fine.
38
+
39
+ **Check:** list each route's links and request them.
40
+
41
+ ```bash
42
+ curl -s localhost:3000/ | grep -o 'href="/[^"#]*"' | cut -d'"' -f2 | sort -u |
43
+ while read -r p; do printf '%s %s\n' "$(curl -so /dev/null -w '%{http_code}' "localhost:3000$p")" "$p"; done
44
+ ```
45
+
46
+ Every line starts with `200`. A broken link in the nav or footer breaks on every
47
+ page, so check those first.
@@ -0,0 +1,39 @@
1
+ # Security and hygiene
2
+
3
+ ## SEC-01 · `NEXT_PUBLIC_` holds only public keys
4
+
5
+ **Must not ship**
6
+
7
+ Anything prefixed `NEXT_PUBLIC_` ships in the browser bundle, readable by
8
+ anyone. Only keys designed to be public belong there: a Sanity project ID, a
9
+ Stripe `pk_` key, an analytics site ID. Read every other secret on the server.
10
+
11
+ **Check:**
12
+
13
+ ```bash
14
+ grep -rhoE 'NEXT_PUBLIC_[A-Z0-9_]+' app components lib | sort -u
15
+ ```
16
+
17
+ Confirm each name on the list is meant to be public.
18
+
19
+ ## SEC-02 · Tracking matches the consent decision
20
+
21
+ **Fix before launch** · only if consent is required
22
+
23
+ No analytics or ad script runs, and no tracking cookie is set, before the
24
+ visitor answers the consent banner. The `ketch-consent-check` skill covers
25
+ gating a script behind Ketch, when the project has it.
26
+
27
+ **Check (browser):** in a fresh private window, before you answer the banner,
28
+ DevTools → Application → Cookies lists no tracking cookies.
29
+
30
+ ## SEC-03 · No first-party console errors
31
+
32
+ **Fix before launch**
33
+
34
+ The console shows no errors from the site's own code on load, and no
35
+ hydration mismatches. A mismatch means the server and the client rendered
36
+ different content. Errors from third-party scripts are out of scope.
37
+
38
+ **Check (browser):** load each route with DevTools open, then read the
39
+ console.
@@ -9,13 +9,13 @@ import { fontsVariable } from "@/lib/styles/fonts";
9
9
  import AppData from "@/package.json";
10
10
  import "@/lib/styles/css/index.css";
11
11
  import { cn } from "@/lib/styles/cn";
12
+ import { getBaseUrl } from "@/lib/utils/url";
12
13
 
13
14
  const APP_NAME = AppData.name;
14
15
  const APP_DEFAULT_TITLE = "Basement Starter";
15
16
  const APP_TITLE_TEMPLATE = "%s - Basement Starter";
16
17
  const APP_DESCRIPTION = AppData.description;
17
- const APP_BASE_URL =
18
- process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";
18
+ const APP_BASE_URL = getBaseUrl();
19
19
 
20
20
  const geist = Geist({
21
21
  subsets: ["latin"],
@@ -1,4 +1,5 @@
1
1
  import type { Metadata } from "next";
2
+ import { getBaseUrl } from "@/lib/utils/url";
2
3
 
3
4
  /**
4
5
  * Metadata Generation Utilities
@@ -26,8 +27,7 @@ interface GenerateMetadataOptions {
26
27
  authors?: string[];
27
28
  }
28
29
 
29
- const APP_BASE_URL =
30
- process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";
30
+ const APP_BASE_URL = getBaseUrl();
31
31
 
32
32
  /**
33
33
  * Generate complete metadata object for pages
@@ -3,15 +3,18 @@
3
3
  *
4
4
  * Priority:
5
5
  * 1. NEXT_PUBLIC_BASE_URL - explicit override (custom domains)
6
- * 2. VERCEL_PROJECT_PRODUCTION_URL - auto-set by Vercel (production domain)
7
- * 3. VERCEL_URL - auto-set by Vercel (preview/branch deploys)
6
+ * 2. VERCEL_PROJECT_PRODUCTION_URL - auto-set by Vercel, on production deployments only
7
+ * 3. VERCEL_URL - the deployment's own URL, so previews never emit production URLs
8
8
  * 4. localhost fallback
9
9
  */
10
10
  export function getBaseUrl(): string {
11
11
  if (process.env.NEXT_PUBLIC_BASE_URL) {
12
12
  return process.env.NEXT_PUBLIC_BASE_URL;
13
13
  }
14
- if (process.env.VERCEL_PROJECT_PRODUCTION_URL) {
14
+ if (
15
+ process.env.VERCEL_ENV === "production" &&
16
+ process.env.VERCEL_PROJECT_PRODUCTION_URL
17
+ ) {
15
18
  return `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`;
16
19
  }
17
20
  if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
@@ -80,7 +80,9 @@ export const RichText = ({ content }: RichTextProps) => {
80
80
  externalLink: LinkMark,
81
81
  },
82
82
  block: {
83
- h1: ({ children }) => <h1 className="h1">{children}</h1>,
83
+ // The h1 style is retired: the page owns its H1, so legacy content
84
+ // drops a level.
85
+ h1: ({ children }) => <h2 className="h2">{children}</h2>,
84
86
  h2: ({ children }) => <h2 className="h2">{children}</h2>,
85
87
  h3: ({ children }) => <h3 className="h3">{children}</h3>,
86
88
  h4: ({ children }) => <h4 className="h4">{children}</h4>,