bsmnt 0.4.3 → 0.6.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 (266) hide show
  1. package/README.md +1 -0
  2. package/dist/application/add-hooks/index.d.ts.map +1 -1
  3. package/dist/application/add-hooks/index.js +1 -0
  4. package/dist/application/add-hooks/index.js.map +1 -1
  5. package/dist/application/add-integration/index.d.ts +33 -8
  6. package/dist/application/add-integration/index.d.ts.map +1 -1
  7. package/dist/application/add-integration/index.js +221 -90
  8. package/dist/application/add-integration/index.js.map +1 -1
  9. package/dist/application/create-project/build-context.d.ts +3 -1
  10. package/dist/application/create-project/build-context.d.ts.map +1 -1
  11. package/dist/application/create-project/build-context.js +2 -1
  12. package/dist/application/create-project/build-context.js.map +1 -1
  13. package/dist/application/create-project/index.d.ts +3 -1
  14. package/dist/application/create-project/index.d.ts.map +1 -1
  15. package/dist/application/create-project/index.js +4 -2
  16. package/dist/application/create-project/index.js.map +1 -1
  17. package/dist/application/create-project/map-selection-to-registry.js +1 -1
  18. package/dist/application/create-project/map-selection-to-registry.js.map +1 -1
  19. package/dist/application/install-skills/index.js +1 -1
  20. package/dist/application/install-skills/index.js.map +1 -1
  21. package/dist/application/shared/project-detection.d.ts +2 -2
  22. package/dist/application/shared/project-detection.d.ts.map +1 -1
  23. package/dist/application/shared/project-detection.js +2 -2
  24. package/dist/application/shared/project-detection.js.map +1 -1
  25. package/dist/core/create/execute-plan.d.ts +4 -0
  26. package/dist/core/create/execute-plan.d.ts.map +1 -1
  27. package/dist/core/create/execute-plan.js +8 -0
  28. package/dist/core/create/execute-plan.js.map +1 -1
  29. package/dist/core/create/internal-ids.d.ts +4 -1
  30. package/dist/core/create/internal-ids.d.ts.map +1 -1
  31. package/dist/core/create/internal-ids.js +6 -1
  32. package/dist/core/create/internal-ids.js.map +1 -1
  33. package/dist/core/create/types.d.ts +2 -0
  34. package/dist/core/create/types.d.ts.map +1 -1
  35. package/dist/domain/cms.d.ts +0 -7
  36. package/dist/domain/cms.d.ts.map +1 -1
  37. package/dist/domain/cms.js.map +1 -1
  38. package/dist/domain/forms.d.ts +17 -0
  39. package/dist/domain/forms.d.ts.map +1 -0
  40. package/dist/domain/forms.js +13 -0
  41. package/dist/domain/forms.js.map +1 -0
  42. package/dist/domain/integration.d.ts +30 -0
  43. package/dist/domain/integration.d.ts.map +1 -0
  44. package/dist/domain/integration.js +12 -0
  45. package/dist/domain/integration.js.map +1 -0
  46. package/dist/domain/skills.d.ts +58 -0
  47. package/dist/domain/skills.d.ts.map +1 -1
  48. package/dist/domain/skills.js +52 -0
  49. package/dist/domain/skills.js.map +1 -1
  50. package/dist/index.js +114 -38
  51. package/dist/index.js.map +1 -1
  52. package/dist/infrastructure/agents/register-sanity-mcp.js +9 -6
  53. package/dist/infrastructure/agents/register-sanity-mcp.js.map +1 -1
  54. package/dist/infrastructure/create/apply-package-json.d.ts.map +1 -1
  55. package/dist/infrastructure/create/apply-package-json.js +19 -0
  56. package/dist/infrastructure/create/apply-package-json.js.map +1 -1
  57. package/dist/infrastructure/create/executor.d.ts.map +1 -1
  58. package/dist/infrastructure/create/executor.js +5 -0
  59. package/dist/infrastructure/create/executor.js.map +1 -1
  60. package/dist/infrastructure/create/install-dependencies.d.ts.map +1 -1
  61. package/dist/infrastructure/create/install-dependencies.js +4 -0
  62. package/dist/infrastructure/create/install-dependencies.js.map +1 -1
  63. package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
  64. package/dist/infrastructure/create/lifecycle-registry.js +2 -0
  65. package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
  66. package/dist/infrastructure/create/merge-registry.d.ts.map +1 -1
  67. package/dist/infrastructure/create/merge-registry.js +8 -0
  68. package/dist/infrastructure/create/merge-registry.js.map +1 -1
  69. package/dist/infrastructure/create/setup-agent.d.ts +2 -0
  70. package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
  71. package/dist/infrastructure/create/setup-agent.js +32 -8
  72. package/dist/infrastructure/create/setup-agent.js.map +1 -1
  73. package/dist/infrastructure/create/setup-dotenvx.d.ts +41 -0
  74. package/dist/infrastructure/create/setup-dotenvx.d.ts.map +1 -0
  75. package/dist/infrastructure/create/setup-dotenvx.js +502 -0
  76. package/dist/infrastructure/create/setup-dotenvx.js.map +1 -0
  77. package/dist/infrastructure/create/setup-sanity.d.ts +13 -1
  78. package/dist/infrastructure/create/setup-sanity.d.ts.map +1 -1
  79. package/dist/infrastructure/create/setup-sanity.js +74 -31
  80. package/dist/infrastructure/create/setup-sanity.js.map +1 -1
  81. package/dist/infrastructure/integrations/inject-integration.d.ts +3 -3
  82. package/dist/infrastructure/integrations/inject-integration.d.ts.map +1 -1
  83. package/dist/infrastructure/integrations/inject-integration.js +81 -37
  84. package/dist/infrastructure/integrations/inject-integration.js.map +1 -1
  85. package/dist/modules/features/cms/sanity/config.d.ts.map +1 -1
  86. package/dist/modules/features/cms/sanity/config.js +13 -6
  87. package/dist/modules/features/cms/sanity/config.js.map +1 -1
  88. package/dist/modules/features/cms/sanity/index.js +8 -2
  89. package/dist/modules/features/cms/sanity/index.js.map +1 -1
  90. package/dist/modules/features/cms/sanity/mergers/ci-workflow.d.ts +13 -0
  91. package/dist/modules/features/cms/sanity/mergers/ci-workflow.d.ts.map +1 -0
  92. package/dist/modules/features/cms/sanity/mergers/ci-workflow.js +38 -0
  93. package/dist/modules/features/cms/sanity/mergers/ci-workflow.js.map +1 -0
  94. package/dist/modules/features/cms/sanity/mergers/knip.d.ts +12 -0
  95. package/dist/modules/features/cms/sanity/mergers/knip.d.ts.map +1 -0
  96. package/dist/modules/features/cms/sanity/mergers/knip.js +38 -0
  97. package/dist/modules/features/cms/sanity/mergers/knip.js.map +1 -0
  98. package/dist/modules/features/cms/sanity/mergers/layout.d.ts.map +1 -1
  99. package/dist/modules/features/cms/sanity/mergers/layout.js +17 -3
  100. package/dist/modules/features/cms/sanity/mergers/layout.js.map +1 -1
  101. package/dist/modules/features/cms/sanity/mergers/sitemap.d.ts +3 -3
  102. package/dist/modules/features/cms/sanity/mergers/sitemap.d.ts.map +1 -1
  103. package/dist/modules/features/cms/sanity/mergers/sitemap.js +48 -62
  104. package/dist/modules/features/cms/sanity/mergers/sitemap.js.map +1 -1
  105. package/dist/modules/features/cms/sanity-pagebuilder/config.d.ts.map +1 -1
  106. package/dist/modules/features/cms/sanity-pagebuilder/config.js +8 -5
  107. package/dist/modules/features/cms/sanity-pagebuilder/config.js.map +1 -1
  108. package/dist/modules/features/cms/sanity-pagebuilder/index.js +2 -2
  109. package/dist/modules/features/cms/sanity-pagebuilder/index.js.map +1 -1
  110. package/dist/modules/features/env/dotenvx/config.d.ts +13 -0
  111. package/dist/modules/features/env/dotenvx/config.d.ts.map +1 -0
  112. package/dist/modules/features/env/dotenvx/config.js +47 -0
  113. package/dist/modules/features/env/dotenvx/config.js.map +1 -0
  114. package/dist/modules/features/forms/hubspot/config.d.ts +31 -0
  115. package/dist/modules/features/forms/hubspot/config.d.ts.map +1 -0
  116. package/dist/modules/features/forms/hubspot/config.js +25 -0
  117. package/dist/modules/features/forms/hubspot/config.js.map +1 -0
  118. package/dist/paths.d.ts +16 -0
  119. package/dist/paths.d.ts.map +1 -1
  120. package/dist/paths.js +16 -0
  121. package/dist/paths.js.map +1 -1
  122. package/package.json +21 -9
  123. package/src/agent-skills/json-ld/SKILL.md +85 -0
  124. package/src/agent-skills/manage-env/SKILL.md +67 -0
  125. package/src/assets/check-node-version.mjs +22 -0
  126. package/src/modules/features/cms/sanity/files/app/blog/[slug]/page.tsx +48 -21
  127. package/src/modules/features/cms/sanity/files/app/blog/page.tsx +54 -0
  128. package/src/modules/features/cms/sanity/files/app/feed.xml/route.ts +36 -0
  129. package/src/modules/features/cms/sanity/files/components/sanity/structured-data.tsx +83 -0
  130. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/components/disable-draft-mode.tsx +3 -3
  131. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/queries.ts +14 -0
  132. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.config.ts +19 -3
  133. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.types.ts +1 -0
  134. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/article.ts +7 -7
  135. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/index.ts +36 -1
  136. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/metadata.ts +12 -1
  137. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data-blocks.ts +416 -0
  138. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data.ts +100 -0
  139. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/structure.ts +37 -2
  140. package/src/modules/features/cms/sanity/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
  141. package/src/modules/features/cms/sanity/files/lib/scripts/setup-ci-secrets.ts +117 -0
  142. package/src/modules/features/cms/sanity/files/lib/utils/rss.ts +96 -0
  143. package/src/modules/features/cms/sanity-pagebuilder/files/.knip.json +8 -0
  144. package/src/modules/features/cms/sanity-pagebuilder/files/app/api/[[...slug]]/route.ts +100 -0
  145. package/src/modules/features/cms/sanity-pagebuilder/files/app/api/draft-mode/disable/route.ts +7 -0
  146. package/src/modules/features/cms/sanity-pagebuilder/files/app/api/draft-mode/enable/route.ts +20 -0
  147. package/src/modules/features/cms/sanity-pagebuilder/files/app/api/revalidate/route.ts +126 -0
  148. package/src/modules/features/cms/sanity-pagebuilder/files/app/feed.xml/route.ts +40 -0
  149. package/src/modules/features/cms/sanity-pagebuilder/files/app/sitemap.md/route.ts +124 -0
  150. package/src/modules/features/cms/sanity-pagebuilder/files/app/studio/[[...tool]]/page.tsx +8 -0
  151. package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/draft-mode-toggle.tsx +27 -0
  152. package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +87 -0
  153. package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/visual-editing.tsx +28 -0
  154. package/src/modules/features/cms/sanity-pagebuilder/files/components/ui/sanity-image/index.tsx +41 -0
  155. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/check-integration.ts +5 -0
  156. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/client.ts +27 -0
  157. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
  158. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-input.tsx +39 -0
  159. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-category-input.tsx +50 -0
  160. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/same-as-input.tsx +66 -0
  161. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-field.tsx +18 -0
  162. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-input.tsx +14 -0
  163. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/confirm-publish-action.ts +40 -0
  164. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/env.ts +34 -0
  165. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/layout.ts +67 -0
  166. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/redirects.ts +17 -0
  167. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +79 -0
  168. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/live/index.tsx +88 -0
  169. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
  170. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +130 -0
  171. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-category.ts +28 -0
  172. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-tree-pane.tsx +420 -0
  173. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/pinned-pages.ts +54 -0
  174. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/presentation.ts +119 -0
  175. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +407 -0
  176. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.cli.ts +29 -0
  177. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +113 -0
  178. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/index.ts +4 -0
  179. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
  180. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
  181. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
  182. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
  183. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/content/author.ts +70 -0
  184. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
  185. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +124 -0
  186. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/company-data.ts +70 -0
  187. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
  188. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/navbar.ts +75 -0
  189. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +120 -0
  190. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +124 -0
  191. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/link.ts +125 -0
  192. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
  193. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/metadata.ts +79 -0
  194. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
  195. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-builder.ts +39 -0
  196. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
  197. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +242 -0
  198. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
  199. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/structured-data-blocks.ts +436 -0
  200. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +51 -0
  201. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/structure.ts +330 -0
  202. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/image.ts +8 -0
  203. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/link.ts +140 -0
  204. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-builder-markdown.ts +81 -0
  205. package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
  206. package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +45 -0
  207. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/check-redirect.ts +30 -0
  208. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/json-ld.tsx +521 -0
  209. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/metadata.ts +167 -0
  210. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/rss.ts +96 -0
  211. package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/sitemap.ts +40 -0
  212. package/src/modules/features/cms/sanity-pagebuilder/files/proxy.ts +81 -0
  213. package/src/modules/features/env/dotenvx/files/decrypt-env.mjs +45 -0
  214. package/src/modules/features/env/dotenvx/files/gitleaks.yml +25 -0
  215. package/src/modules/features/env/dotenvx/files/instrumentation.ts +14 -0
  216. package/src/modules/features/env/dotenvx/files/push-keys.mjs +129 -0
  217. package/src/modules/features/env/dotenvx/files/save-key.mjs +108 -0
  218. package/src/modules/features/env/dotenvx/files/setup-env.mjs +67 -0
  219. package/src/modules/features/env/dotenvx/files/vercelignore +4 -0
  220. package/src/modules/features/env/dotenvx/files/write-env.mjs +47 -0
  221. package/src/templates/next-default/.env.example +14 -6
  222. package/src/templates/next-default/.github/workflows/ci.yml +83 -0
  223. package/src/templates/next-default/.vscode/extensions.json +3 -0
  224. package/src/templates/next-default/README.md +53 -0
  225. package/src/templates/next-default/knip.json +14 -0
  226. package/src/templates/next-default/lefthook.yml +5 -0
  227. package/src/templates/next-default/lib/utils/json-ld.tsx +327 -21
  228. package/src/templates/next-default/next.config.ts +6 -0
  229. package/src/templates/next-default/package.json +8 -4
  230. package/src/templates/next-experiments/.env.example +14 -6
  231. package/src/templates/next-experiments/.github/workflows/ci.yml +83 -0
  232. package/src/templates/next-experiments/.vscode/extensions.json +3 -0
  233. package/src/templates/next-experiments/README.md +53 -0
  234. package/src/templates/next-experiments/knip.json +14 -0
  235. package/src/templates/next-experiments/lefthook.yml +30 -0
  236. package/src/templates/next-experiments/lib/utils/json-ld.tsx +327 -21
  237. package/src/templates/next-experiments/next.config.ts +6 -0
  238. package/src/templates/next-experiments/package.json +10 -2
  239. package/src/templates/next-pagebuilder/.env.example +19 -1
  240. package/src/templates/next-pagebuilder/.github/workflows/ci.yml +90 -0
  241. package/src/templates/next-pagebuilder/.vscode/extensions.json +3 -0
  242. package/src/templates/next-pagebuilder/README.md +65 -0
  243. package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +6 -1
  244. package/src/templates/next-pagebuilder/app/(content)/layout.tsx +3 -12
  245. package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +11 -10
  246. package/src/templates/next-pagebuilder/components/layout/header/index.tsx +5 -3
  247. package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +38 -26
  248. package/src/templates/next-pagebuilder/components/layout/wrapper/index.tsx +3 -11
  249. package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/index.tsx +1 -1
  250. package/src/templates/next-pagebuilder/components/page-document/index.tsx +38 -0
  251. package/src/templates/next-pagebuilder/knip.json +27 -0
  252. package/src/templates/next-pagebuilder/lefthook.yml +5 -0
  253. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +36 -2
  254. package/src/templates/next-pagebuilder/lib/scripts/setup-ci-secrets.ts +117 -0
  255. package/src/templates/next-pagebuilder/next.config.ts +6 -0
  256. package/src/templates/next-pagebuilder/package.json +9 -3
  257. package/src/templates/next-webgl/.env.example +14 -6
  258. package/src/templates/next-webgl/.github/workflows/ci.yml +83 -0
  259. package/src/templates/next-webgl/.vscode/extensions.json +3 -0
  260. package/src/templates/next-webgl/README.md +53 -0
  261. package/src/templates/next-webgl/knip.json +13 -0
  262. package/src/templates/next-webgl/lefthook.yml +5 -0
  263. package/src/templates/next-webgl/lib/utils/json-ld.tsx +327 -21
  264. package/src/templates/next-webgl/next.config.ts +6 -0
  265. package/src/templates/next-webgl/package.json +8 -4
  266. package/src/modules/features/cms/sanity/files/lib/utils/json-ld.tsx +0 -244
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Push CI environment to GitHub Actions for this repository.
3
+ *
4
+ * Reads values from `.env.local` and sets them on the current repo via the
5
+ * GitHub CLI (`gh`), matching the `build` step in `.github/workflows/ci.yml`:
6
+ * the public Sanity project ID and dataset become repository *variables*, and
7
+ * the read token becomes a *secret*.
8
+ *
9
+ * Run once the repo exists on GitHub: `bun run ci:secrets`
10
+ * Requires the GitHub CLI, authenticated (`gh auth login`).
11
+ */
12
+ import { execFileSync } from "node:child_process"
13
+ import { existsSync, readFileSync } from "node:fs"
14
+ import path from "node:path"
15
+
16
+ const ENV_FILE = ".env.local"
17
+
18
+ /** Public config — stored as GitHub Actions repository variables. */
19
+ const VARIABLES = [
20
+ "NEXT_PUBLIC_SANITY_PROJECT_ID",
21
+ "NEXT_PUBLIC_SANITY_DATASET",
22
+ ] as const
23
+
24
+ /** Sensitive config — stored as GitHub Actions secrets. */
25
+ const SECRETS = ["SANITY_API_READ_TOKEN"] as const
26
+
27
+ function parseEnvFile(file: string): Record<string, string> {
28
+ const env: Record<string, string> = {}
29
+ if (!existsSync(file)) return env
30
+
31
+ for (const rawLine of readFileSync(file, "utf8").split("\n")) {
32
+ const line = rawLine.trim()
33
+ if (!line || line.startsWith("#")) continue
34
+
35
+ const eq = line.indexOf("=")
36
+ if (eq === -1) continue
37
+
38
+ const key = line.slice(0, eq).trim()
39
+ let value = line.slice(eq + 1).trim()
40
+ if (
41
+ (value.startsWith('"') && value.endsWith('"')) ||
42
+ (value.startsWith("'") && value.endsWith("'"))
43
+ ) {
44
+ value = value.slice(1, -1)
45
+ }
46
+ env[key] = value
47
+ }
48
+
49
+ return env
50
+ }
51
+
52
+ function ensureGitHubRepo(): void {
53
+ try {
54
+ execFileSync("gh", ["--version"], { stdio: "pipe" })
55
+ } catch {
56
+ console.error(
57
+ "✖ GitHub CLI (gh) not found. Install it: https://cli.github.com",
58
+ )
59
+ process.exit(1)
60
+ }
61
+
62
+ try {
63
+ execFileSync("gh", ["repo", "view", "--json", "nameWithOwner"], {
64
+ stdio: "pipe",
65
+ })
66
+ } catch {
67
+ console.error("✖ No GitHub repository detected for this directory.")
68
+ console.error(
69
+ " Create and push the repo first (e.g. `gh repo create`), then re-run.",
70
+ )
71
+ process.exit(1)
72
+ }
73
+ }
74
+
75
+ ensureGitHubRepo()
76
+
77
+ const env = parseEnvFile(path.resolve(ENV_FILE))
78
+ let pushed = 0
79
+ let skipped = 0
80
+
81
+ for (const name of VARIABLES) {
82
+ const value = env[name] ?? process.env[name]
83
+ if (!value) {
84
+ console.info(`- ${name}: not found in ${ENV_FILE}, skipping`)
85
+ skipped++
86
+ continue
87
+ }
88
+ // Public value — safe to pass on the command line.
89
+ execFileSync("gh", ["variable", "set", name, "--body", value], {
90
+ stdio: "pipe",
91
+ })
92
+ console.info(`✓ variable ${name}`)
93
+ pushed++
94
+ }
95
+
96
+ for (const name of SECRETS) {
97
+ const value = env[name] ?? process.env[name]
98
+ if (!value) {
99
+ console.info(`- ${name}: not found in ${ENV_FILE}, skipping`)
100
+ skipped++
101
+ continue
102
+ }
103
+ // Sensitive — pipe via stdin so the token never appears in the process args.
104
+ execFileSync("gh", ["secret", "set", name], { input: value, stdio: "pipe" })
105
+ console.info(`✓ secret ${name}`)
106
+ pushed++
107
+ }
108
+
109
+ if (pushed === 0) {
110
+ console.info(
111
+ `\nNothing to sync. Add your Sanity values to ${ENV_FILE} (or run Sanity setup) first.`,
112
+ )
113
+ } else {
114
+ console.info(
115
+ `\nDone — ${String(pushed)} value(s) pushed to GitHub Actions${skipped ? `, ${String(skipped)} skipped` : ""}.`,
116
+ )
117
+ }
@@ -5,6 +5,12 @@ const nextConfig: NextConfig = {
5
5
  reactStrictMode: true,
6
6
  reactCompiler: true,
7
7
  typedRoutes: true,
8
+ // Bundle the committed encrypted env files into serverless functions so
9
+ // instrumentation.ts can decrypt them at runtime. .env.keys is never listed
10
+ // (and is git/vercel-ignored); missing files are skipped.
11
+ outputFileTracingIncludes: {
12
+ "/**": ["./.env", "./.env.production", "./.env.preview"],
13
+ },
8
14
  turbopack: {
9
15
  rules: {
10
16
  "*.svg": {
@@ -3,14 +3,19 @@
3
3
  "description": "Basement Next.js starter template",
4
4
  "version": "0.1.0",
5
5
  "private": true,
6
+ "packageManager": "bun@1.3.14",
7
+ "engines": {
8
+ "node": ">=24"
9
+ },
6
10
  "scripts": {
7
11
  "analyze": "cross-env ANALYZE=true bun run build",
8
12
  "analyze:experimental": "next experimental-analyze",
9
13
  "build": "next build",
14
+ "ci:secrets": "bun ./lib/scripts/setup-ci-secrets.ts",
10
15
  "dev": "next dev",
11
16
  "format": "biome format --write .",
12
- "knip": "bunx knip",
13
- "knip:fix": "bunx knip --fix",
17
+ "knip": "knip",
18
+ "knip:fix": "knip --fix",
14
19
  "lighthouse": "bunx @unlighthouse/cli --site http://localhost:3000",
15
20
  "lint": "biome lint --max-diagnostics=200",
16
21
  "lint:fix": "biome check --write --unsafe --max-diagnostics=200",
@@ -37,12 +42,13 @@
37
42
  "@svgr/webpack": "^8.1.0",
38
43
  "@tailwindcss/postcss": "^4.2.2",
39
44
  "@types/bun": "^1.3.11",
40
- "@types/node": "^25.5.0",
45
+ "@types/node": "^24.13.1",
41
46
  "@types/react": "^19.2.14",
42
47
  "@types/react-dom": "^19.2.3",
43
48
  "@typescript/native-preview": "^7.0.0-dev.20260323.1",
44
49
  "babel-plugin-react-compiler": "^1.0.0",
45
50
  "cross-env": "^10.1.0",
51
+ "knip": "^6.16.1",
46
52
  "lefthook": "^1.13.0",
47
53
  "postcss-functions": "^4.0.2",
48
54
  "postcss-preset-env": "^11.2.0",
@@ -1,11 +1,19 @@
1
1
  # ============================================
2
2
  # Basement Next Starter - Environment Variables
3
3
  # ============================================
4
- # Copy this file to .env.local and fill in the values
5
- # Run: cp .env.example .env.local
4
+ # This project uses dotenvx (https://dotenvx.com): the committed `.env` holds
5
+ # shared values, with secrets encrypted there. The private keys live in
6
+ # `.env.keys` (gitignored) — restore them with `bun run env:setup`.
6
7
  #
7
- # Only configure the integrations you need.
8
- # Remove unused sections to keep your env file clean.
8
+ # Add or change a variable in `.env` (not .env.local):
9
+ # - Secret (API key, token, …): bun run env:set KEY value (--preview / --prod)
10
+ # - Trivial / NEXT_PUBLIC_*: bun run env:set KEY value --plain
11
+ # - Bulk-encrypt a file edited by hand: bun run env:encrypt-all (--preview / --prod)
12
+ #
13
+ # Edge runtime (middleware, `runtime = "edge"`): dotenvx can't decrypt there.
14
+ # Set any secret those read directly in Vercel's env vars, not here.
15
+ #
16
+ # This file just documents the available variables; real values live in `.env`.
9
17
  # ============================================
10
18
 
11
19
 
@@ -16,7 +24,7 @@
16
24
  # Base URL for your site (used for SEO, canonical URLs, etc.)
17
25
  # Development: http://localhost:3000
18
26
  # Production: https://your-domain.com
19
- NEXT_PUBLIC_BASE_URL="http://localhost:3000"
27
+ NEXT_PUBLIC_BASE_URL=""
20
28
 
21
29
  # Draft mode secret for preview functionality
22
30
  # Generate a random string: openssl rand -base64 32
@@ -32,7 +40,7 @@ DRAFT_MODE_TOKEN=""
32
40
 
33
41
  # Required for Sanity
34
42
  NEXT_PUBLIC_SANITY_PROJECT_ID=""
35
- NEXT_PUBLIC_SANITY_DATASET="production"
43
+ NEXT_PUBLIC_SANITY_DATASET=""
36
44
  NEXT_PUBLIC_SANITY_API_READ_TOKEN=""
37
45
 
38
46
  # Optional - for server-side mutations and visual editing
@@ -0,0 +1,83 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+ push:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+ ci:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ # Node version is read from .nvmrc — the single source of truth.
20
+ - name: Setup Node
21
+ uses: actions/setup-node@v4
22
+ with:
23
+ node-version-file: ".nvmrc"
24
+
25
+ # Bun version is read from package.json's "packageManager" field — the
26
+ # single source of truth. Do NOT pin a version here, or the two can drift.
27
+ - name: Setup Bun
28
+ uses: oven-sh/setup-bun@v2
29
+
30
+ # Cache Bun's global install cache so dependencies aren't re-downloaded
31
+ # on every run. Keyed on the lockfile so it busts when deps change.
32
+ - name: Cache Bun dependencies
33
+ uses: actions/cache@v4
34
+ with:
35
+ path: ~/.bun/install/cache
36
+ key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
37
+ restore-keys: |
38
+ ${{ runner.os }}-bun-
39
+
40
+ - name: Install dependencies
41
+ run: bun install --frozen-lockfile
42
+
43
+ - name: Type check
44
+ run: bun run typecheck:compare
45
+
46
+ - name: Lint
47
+ run: bun run lint
48
+
49
+ # dotenvx needs the private key to decrypt secrets at build time. It's
50
+ # pulled from 1Password via an org-wide service-account token + the op-ref
51
+ # committed in .env. Optional: builds pass without it (only plaintext /
52
+ # NEXT_PUBLIC_* is read), and a per-repo DOTENV_PRIVATE_KEY secret still
53
+ # works as a fallback.
54
+ - name: Install 1Password CLI
55
+ if: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN != '' }}
56
+ uses: 1password/install-cli-action@v1
57
+
58
+ - name: Build
59
+ env:
60
+ OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
61
+ DOTENV_PRIVATE_KEY: ${{ secrets.DOTENV_PRIVATE_KEY }}
62
+ run: |
63
+ if [ -n "$OP_SERVICE_ACCOUNT_TOKEN" ]; then
64
+ ref="$(grep -m1 '^DOTENV_PRIVATE_KEY_OP_REF=' .env | cut -d= -f2-)"
65
+ if [ -n "$ref" ]; then
66
+ DOTENV_PRIVATE_KEY="$(op read "$ref")"
67
+ echo "::add-mask::$DOTENV_PRIVATE_KEY"
68
+ export DOTENV_PRIVATE_KEY
69
+ fi
70
+ fi
71
+ bun run build
72
+
73
+ # Runs your tests if any exist; a fresh project with none passes cleanly.
74
+ - name: Test
75
+ run: |
76
+ if git ls-files '*.test.*' '*.spec.*' '*_test.*' '*_spec.*' | grep -q .; then
77
+ bun test
78
+ else
79
+ echo "No test files found — skipping bun test."
80
+ fi
81
+
82
+ - name: Knip
83
+ run: bun run knip
@@ -10,6 +10,9 @@
10
10
  // Sanity CMS (GROQ syntax + validation)
11
11
  "sanity-io.vscode-sanity",
12
12
 
13
+ // Env (dotenvx — view decrypted .env values inline)
14
+ "dotenv.dotenvx-vscode",
15
+
13
16
  // DX Enhancements
14
17
  "yoavbls.pretty-ts-errors"
15
18
  ]
@@ -22,6 +22,35 @@ bun dev
22
22
  | `bun format` | Format the codebase |
23
23
  | `bun typecheck` | Run TypeScript |
24
24
  | `bun analyze` | Analyze the Next.js bundle |
25
+ | `bun env:set KEY value` | Encrypt one value into `.env` (`--plain`, `--preview`/`--prod`) |
26
+ | `bun env:encrypt-all` | Bulk-encrypt every plaintext value in a file (`--preview`/`--prod`) |
27
+ | `bun env:setup` | Restore `.env.keys` from 1Password |
28
+ | `bun env:view` | Print the decrypted `.env` (`--preview` / `--prod`) |
29
+ | `bun env:setup-remote` | Push private keys to GitHub / Vercel (`github`/`vercel`, or pick) |
30
+ | `bun env:save` | Save the private key to 1Password (Development vault) |
31
+
32
+ ## Environment variables
33
+
34
+ Secrets are encrypted at rest with [dotenvx](https://dotenvx.com): the committed `.env` holds encrypted values, the private keys live in `.env.keys` (gitignored), and dev/build run through `dotenvx run` so values decrypt automatically.
35
+
36
+ **First run.** `bun install` restores `.env.keys` from 1Password (via `DOTENV_PRIVATE_KEY_OP_REF` in `.env`), or run `bun run env:setup`. Needs 1Password access + the `op` CLI:
37
+
38
+ - macOS: `brew install --cask 1password-cli`
39
+ - Windows: `winget install 1password-cli`
40
+ - Linux / other: [1Password CLI docs](https://developer.1password.com/docs/cli/get-started/)
41
+
42
+ **Add or change a variable** (in `.env`):
43
+
44
+ - Secret: `bun run env:set KEY value` (`--preview`/`--prod` to target an environment)
45
+ - Public / `NEXT_PUBLIC_*`: `bun run env:set KEY value --plain`
46
+ - Bulk-encrypt a hand-edited file: `bun run env:encrypt-all`
47
+ - Inspect: `bun run env:view` (`--preview`/`--prod`)
48
+
49
+ **Per environment.** Scripts load `.env.$VERCEL_ENV` over `.env`. After adding a per-env file, push its key with `bun run env:setup-remote vercel` — `instrumentation.ts` uses it to decrypt at runtime.
50
+
51
+ **Edge runtime.** dotenvx decrypts only in the Node runtime; secrets read in `middleware.ts` or a `runtime = "edge"` route must be set as plain Vercel env vars.
52
+
53
+ A gitleaks pre-commit hook + CI scan block committed plaintext secrets (install: `brew install gitleaks`).
25
54
 
26
55
  ## Project Structure
27
56
 
@@ -49,3 +78,27 @@ lib/
49
78
  - Edit `lib/styles/tokens.css` for theme variables, breakpoints, and custom Tailwind utilities.
50
79
  - Edit `lib/styles/global.css` for reset rules and app-wide global styles.
51
80
  - `lib/styles/fonts.ts` handles font variables.
81
+
82
+ ## Continuous Integration
83
+
84
+ A GitHub Actions workflow (`.github/workflows/ci.yml`) runs on every pull request to `main` and on pushes to `main`. It runs type checking, linting, the production build, tests, and `knip`.
85
+
86
+ The workflow takes its runtime versions from your manifests, so there's a single source of truth and nothing to keep in sync by hand:
87
+
88
+ - **Node** comes from `.nvmrc`.
89
+ - **Bun** comes from the `packageManager` field in `package.json`.
90
+
91
+ It also caches Bun's install cache between runs, and the test step is a no-op until you add real test files.
92
+
93
+ The build decrypts the committed `.env` with the dotenvx private key, pulled from 1Password: set an **org-level** `OP_SERVICE_ACCOUNT_TOKEN` (a read-only [service account](https://developer.1password.com/docs/service-accounts/) scoped to the `Development` vault) — one secret for every repo — and CI reads the key via the op-ref committed in `.env`. A per-repo `DOTENV_PRIVATE_KEY` secret (`bun run env:setup-remote github`) works as a fallback; builds pass without either (only plaintext / `NEXT_PUBLIC_*` is read).
94
+
95
+ ### Branch protection
96
+
97
+ To block merges when CI fails, enable branch protection on `main`:
98
+
99
+ 1. Go to **Settings → Branches → Add branch ruleset** (or **Add rule**).
100
+ 2. Target the `main` branch.
101
+ 3. Enable **Require status checks to pass before merging** and select the **CI** check.
102
+ 4. (Recommended) Enable **Require a pull request before merging**.
103
+
104
+ Pull requests then cannot be merged until the CI workflow passes.
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://unpkg.com/knip@6/schema.json",
3
+ "entry": [
4
+ "lib/scripts/**/*.{ts,tsx}",
5
+ "lib/hooks/**/*.{ts,tsx}",
6
+ "lib/utils/**/*.{ts,tsx}",
7
+ "components/**/*.{ts,tsx}"
8
+ ],
9
+ "ignoreDependencies": [
10
+ "zod",
11
+ "@svgr/webpack"
12
+ ]
13
+ }
@@ -14,6 +14,11 @@ pre-commit:
14
14
  run: bunx tsgo --noEmit --incremental false
15
15
  stage_fixed: false
16
16
 
17
+ pre-push:
18
+ commands:
19
+ knip:
20
+ run: bun run knip
21
+
17
22
  post-merge:
18
23
  commands:
19
24
  install-deps: