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.
- package/README.md +1 -0
- package/dist/application/add-hooks/index.d.ts.map +1 -1
- package/dist/application/add-hooks/index.js +1 -0
- package/dist/application/add-hooks/index.js.map +1 -1
- package/dist/application/add-integration/index.d.ts +33 -8
- package/dist/application/add-integration/index.d.ts.map +1 -1
- package/dist/application/add-integration/index.js +221 -90
- package/dist/application/add-integration/index.js.map +1 -1
- package/dist/application/create-project/build-context.d.ts +3 -1
- package/dist/application/create-project/build-context.d.ts.map +1 -1
- package/dist/application/create-project/build-context.js +2 -1
- package/dist/application/create-project/build-context.js.map +1 -1
- package/dist/application/create-project/index.d.ts +3 -1
- package/dist/application/create-project/index.d.ts.map +1 -1
- package/dist/application/create-project/index.js +4 -2
- package/dist/application/create-project/index.js.map +1 -1
- package/dist/application/create-project/map-selection-to-registry.js +1 -1
- package/dist/application/create-project/map-selection-to-registry.js.map +1 -1
- package/dist/application/install-skills/index.js +1 -1
- package/dist/application/install-skills/index.js.map +1 -1
- package/dist/application/shared/project-detection.d.ts +2 -2
- package/dist/application/shared/project-detection.d.ts.map +1 -1
- package/dist/application/shared/project-detection.js +2 -2
- package/dist/application/shared/project-detection.js.map +1 -1
- package/dist/core/create/execute-plan.d.ts +4 -0
- package/dist/core/create/execute-plan.d.ts.map +1 -1
- package/dist/core/create/execute-plan.js +8 -0
- package/dist/core/create/execute-plan.js.map +1 -1
- package/dist/core/create/internal-ids.d.ts +4 -1
- package/dist/core/create/internal-ids.d.ts.map +1 -1
- package/dist/core/create/internal-ids.js +6 -1
- package/dist/core/create/internal-ids.js.map +1 -1
- package/dist/core/create/types.d.ts +2 -0
- package/dist/core/create/types.d.ts.map +1 -1
- package/dist/domain/cms.d.ts +0 -7
- package/dist/domain/cms.d.ts.map +1 -1
- package/dist/domain/cms.js.map +1 -1
- package/dist/domain/forms.d.ts +17 -0
- package/dist/domain/forms.d.ts.map +1 -0
- package/dist/domain/forms.js +13 -0
- package/dist/domain/forms.js.map +1 -0
- package/dist/domain/integration.d.ts +30 -0
- package/dist/domain/integration.d.ts.map +1 -0
- package/dist/domain/integration.js +12 -0
- package/dist/domain/integration.js.map +1 -0
- package/dist/domain/skills.d.ts +58 -0
- package/dist/domain/skills.d.ts.map +1 -1
- package/dist/domain/skills.js +52 -0
- package/dist/domain/skills.js.map +1 -1
- package/dist/index.js +114 -38
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/agents/register-sanity-mcp.js +9 -6
- package/dist/infrastructure/agents/register-sanity-mcp.js.map +1 -1
- package/dist/infrastructure/create/apply-package-json.d.ts.map +1 -1
- package/dist/infrastructure/create/apply-package-json.js +19 -0
- package/dist/infrastructure/create/apply-package-json.js.map +1 -1
- package/dist/infrastructure/create/executor.d.ts.map +1 -1
- package/dist/infrastructure/create/executor.js +5 -0
- package/dist/infrastructure/create/executor.js.map +1 -1
- package/dist/infrastructure/create/install-dependencies.d.ts.map +1 -1
- package/dist/infrastructure/create/install-dependencies.js +4 -0
- package/dist/infrastructure/create/install-dependencies.js.map +1 -1
- package/dist/infrastructure/create/lifecycle-registry.d.ts.map +1 -1
- package/dist/infrastructure/create/lifecycle-registry.js +2 -0
- package/dist/infrastructure/create/lifecycle-registry.js.map +1 -1
- package/dist/infrastructure/create/merge-registry.d.ts.map +1 -1
- package/dist/infrastructure/create/merge-registry.js +8 -0
- package/dist/infrastructure/create/merge-registry.js.map +1 -1
- package/dist/infrastructure/create/setup-agent.d.ts +2 -0
- package/dist/infrastructure/create/setup-agent.d.ts.map +1 -1
- package/dist/infrastructure/create/setup-agent.js +32 -8
- package/dist/infrastructure/create/setup-agent.js.map +1 -1
- package/dist/infrastructure/create/setup-dotenvx.d.ts +41 -0
- package/dist/infrastructure/create/setup-dotenvx.d.ts.map +1 -0
- package/dist/infrastructure/create/setup-dotenvx.js +502 -0
- package/dist/infrastructure/create/setup-dotenvx.js.map +1 -0
- package/dist/infrastructure/create/setup-sanity.d.ts +13 -1
- package/dist/infrastructure/create/setup-sanity.d.ts.map +1 -1
- package/dist/infrastructure/create/setup-sanity.js +74 -31
- package/dist/infrastructure/create/setup-sanity.js.map +1 -1
- package/dist/infrastructure/integrations/inject-integration.d.ts +3 -3
- package/dist/infrastructure/integrations/inject-integration.d.ts.map +1 -1
- package/dist/infrastructure/integrations/inject-integration.js +81 -37
- package/dist/infrastructure/integrations/inject-integration.js.map +1 -1
- package/dist/modules/features/cms/sanity/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/config.js +13 -6
- package/dist/modules/features/cms/sanity/config.js.map +1 -1
- package/dist/modules/features/cms/sanity/index.js +8 -2
- package/dist/modules/features/cms/sanity/index.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/ci-workflow.d.ts +13 -0
- package/dist/modules/features/cms/sanity/mergers/ci-workflow.d.ts.map +1 -0
- package/dist/modules/features/cms/sanity/mergers/ci-workflow.js +38 -0
- package/dist/modules/features/cms/sanity/mergers/ci-workflow.js.map +1 -0
- package/dist/modules/features/cms/sanity/mergers/knip.d.ts +12 -0
- package/dist/modules/features/cms/sanity/mergers/knip.d.ts.map +1 -0
- package/dist/modules/features/cms/sanity/mergers/knip.js +38 -0
- package/dist/modules/features/cms/sanity/mergers/knip.js.map +1 -0
- package/dist/modules/features/cms/sanity/mergers/layout.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/layout.js +17 -3
- package/dist/modules/features/cms/sanity/mergers/layout.js.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/sitemap.d.ts +3 -3
- package/dist/modules/features/cms/sanity/mergers/sitemap.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity/mergers/sitemap.js +48 -62
- package/dist/modules/features/cms/sanity/mergers/sitemap.js.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/config.d.ts.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/config.js +8 -5
- package/dist/modules/features/cms/sanity-pagebuilder/config.js.map +1 -1
- package/dist/modules/features/cms/sanity-pagebuilder/index.js +2 -2
- package/dist/modules/features/cms/sanity-pagebuilder/index.js.map +1 -1
- package/dist/modules/features/env/dotenvx/config.d.ts +13 -0
- package/dist/modules/features/env/dotenvx/config.d.ts.map +1 -0
- package/dist/modules/features/env/dotenvx/config.js +47 -0
- package/dist/modules/features/env/dotenvx/config.js.map +1 -0
- package/dist/modules/features/forms/hubspot/config.d.ts +31 -0
- package/dist/modules/features/forms/hubspot/config.d.ts.map +1 -0
- package/dist/modules/features/forms/hubspot/config.js +25 -0
- package/dist/modules/features/forms/hubspot/config.js.map +1 -0
- package/dist/paths.d.ts +16 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +16 -0
- package/dist/paths.js.map +1 -1
- package/package.json +21 -9
- package/src/agent-skills/json-ld/SKILL.md +85 -0
- package/src/agent-skills/manage-env/SKILL.md +67 -0
- package/src/assets/check-node-version.mjs +22 -0
- package/src/modules/features/cms/sanity/files/app/blog/[slug]/page.tsx +48 -21
- package/src/modules/features/cms/sanity/files/app/blog/page.tsx +54 -0
- package/src/modules/features/cms/sanity/files/app/feed.xml/route.ts +36 -0
- package/src/modules/features/cms/sanity/files/components/sanity/structured-data.tsx +83 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/components/disable-draft-mode.tsx +3 -3
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/queries.ts +14 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.config.ts +19 -3
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/sanity.types.ts +1 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/article.ts +7 -7
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/index.ts +36 -1
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/metadata.ts +12 -1
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data-blocks.ts +416 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/schemas/structured-data.ts +100 -0
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/structure.ts +37 -2
- package/src/modules/features/cms/sanity/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
- package/src/modules/features/cms/sanity/files/lib/scripts/setup-ci-secrets.ts +117 -0
- package/src/modules/features/cms/sanity/files/lib/utils/rss.ts +96 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/.knip.json +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/[[...slug]]/route.ts +100 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/draft-mode/disable/route.ts +7 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/draft-mode/enable/route.ts +20 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/api/revalidate/route.ts +126 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/feed.xml/route.ts +40 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/sitemap.md/route.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/app/studio/[[...tool]]/page.tsx +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/draft-mode-toggle.tsx +27 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/rich-text.tsx +87 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/components/sanity/visual-editing.tsx +28 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/components/ui/sanity-image/index.tsx +41 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/check-integration.ts +5 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/client.ts +27 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-builder-input.tsx +39 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/page-category-input.tsx +50 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/same-as-input.tsx +66 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-field.tsx +18 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/components/slug-input.tsx +14 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/confirm-publish-action.ts +40 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/env.ts +34 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/layout.ts +67 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/fetchers/redirects.ts +17 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/icons.ts +79 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/live/index.tsx +88 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-builder-config.ts +130 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-category.ts +28 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/page-tree-pane.tsx +420 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/pinned-pages.ts +54 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/presentation.ts +119 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/queries.ts +407 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.cli.ts +29 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/sanity.config.ts +113 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/index.ts +4 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/content/author.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/index.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/company-data.ts +70 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/navbar.ts +75 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/redirect.ts +120 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/layout/structured-data.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/link.ts +125 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/metadata.ts +79 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-builder.ts +39 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/page.ts +242 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/schemas/shared/structured-data-blocks.ts +436 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/singletons.ts +51 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/structure.ts +330 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/image.ts +8 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/link.ts +140 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-builder-markdown.ts +81 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/integrations/sanity/utils/page-json-ld.ts +208 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/scripts/sanity-typegen.ts +45 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/check-redirect.ts +30 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/json-ld.tsx +521 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/metadata.ts +167 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/rss.ts +96 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/lib/utils/sitemap.ts +40 -0
- package/src/modules/features/cms/sanity-pagebuilder/files/proxy.ts +81 -0
- package/src/modules/features/env/dotenvx/files/decrypt-env.mjs +45 -0
- package/src/modules/features/env/dotenvx/files/gitleaks.yml +25 -0
- package/src/modules/features/env/dotenvx/files/instrumentation.ts +14 -0
- package/src/modules/features/env/dotenvx/files/push-keys.mjs +129 -0
- package/src/modules/features/env/dotenvx/files/save-key.mjs +108 -0
- package/src/modules/features/env/dotenvx/files/setup-env.mjs +67 -0
- package/src/modules/features/env/dotenvx/files/vercelignore +4 -0
- package/src/modules/features/env/dotenvx/files/write-env.mjs +47 -0
- package/src/templates/next-default/.env.example +14 -6
- package/src/templates/next-default/.github/workflows/ci.yml +83 -0
- package/src/templates/next-default/.vscode/extensions.json +3 -0
- package/src/templates/next-default/README.md +53 -0
- package/src/templates/next-default/knip.json +14 -0
- package/src/templates/next-default/lefthook.yml +5 -0
- package/src/templates/next-default/lib/utils/json-ld.tsx +327 -21
- package/src/templates/next-default/next.config.ts +6 -0
- package/src/templates/next-default/package.json +8 -4
- package/src/templates/next-experiments/.env.example +14 -6
- package/src/templates/next-experiments/.github/workflows/ci.yml +83 -0
- package/src/templates/next-experiments/.vscode/extensions.json +3 -0
- package/src/templates/next-experiments/README.md +53 -0
- package/src/templates/next-experiments/knip.json +14 -0
- package/src/templates/next-experiments/lefthook.yml +30 -0
- package/src/templates/next-experiments/lib/utils/json-ld.tsx +327 -21
- package/src/templates/next-experiments/next.config.ts +6 -0
- package/src/templates/next-experiments/package.json +10 -2
- package/src/templates/next-pagebuilder/.env.example +19 -1
- package/src/templates/next-pagebuilder/.github/workflows/ci.yml +90 -0
- package/src/templates/next-pagebuilder/.vscode/extensions.json +3 -0
- package/src/templates/next-pagebuilder/README.md +65 -0
- package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +6 -1
- package/src/templates/next-pagebuilder/app/(content)/layout.tsx +3 -12
- package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +11 -10
- package/src/templates/next-pagebuilder/components/layout/header/index.tsx +5 -3
- package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +38 -26
- package/src/templates/next-pagebuilder/components/layout/wrapper/index.tsx +3 -11
- package/src/templates/next-pagebuilder/components/page-builder/components/content-collection/index.tsx +1 -1
- package/src/templates/next-pagebuilder/components/page-document/index.tsx +38 -0
- package/src/templates/next-pagebuilder/knip.json +27 -0
- package/src/templates/next-pagebuilder/lefthook.yml +5 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.types.ts +36 -2
- package/src/templates/next-pagebuilder/lib/scripts/setup-ci-secrets.ts +117 -0
- package/src/templates/next-pagebuilder/next.config.ts +6 -0
- package/src/templates/next-pagebuilder/package.json +9 -3
- package/src/templates/next-webgl/.env.example +14 -6
- package/src/templates/next-webgl/.github/workflows/ci.yml +83 -0
- package/src/templates/next-webgl/.vscode/extensions.json +3 -0
- package/src/templates/next-webgl/README.md +53 -0
- package/src/templates/next-webgl/knip.json +13 -0
- package/src/templates/next-webgl/lefthook.yml +5 -0
- package/src/templates/next-webgl/lib/utils/json-ld.tsx +327 -21
- package/src/templates/next-webgl/next.config.ts +6 -0
- package/src/templates/next-webgl/package.json +8 -4
- package/src/modules/features/cms/sanity/files/lib/utils/json-ld.tsx +0 -244
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HubSpot integration configuration manifest.
|
|
3
|
+
* Single source of truth for dependencies, scripts, paths, and merge rules.
|
|
4
|
+
*
|
|
5
|
+
* The core is dependency-free: it loads HubSpot's official forms script at
|
|
6
|
+
* runtime and styles the injected DOM with self-contained CSS.
|
|
7
|
+
*/
|
|
8
|
+
import type { IntegrationId } from "../../../../domain/integration.js";
|
|
9
|
+
/**
|
|
10
|
+
* A path copied only when another integration is already present in the target
|
|
11
|
+
* project. Used to ship the optional Sanity Studio form picker.
|
|
12
|
+
*/
|
|
13
|
+
export interface ConditionalPath {
|
|
14
|
+
/** Source path relative to this integration's `files/` directory. */
|
|
15
|
+
src: string;
|
|
16
|
+
/** Destination path relative to the project root (before `src/` prefixing). */
|
|
17
|
+
dest: string;
|
|
18
|
+
/** Integration that must already exist for the copy to run. */
|
|
19
|
+
requires: IntegrationId;
|
|
20
|
+
}
|
|
21
|
+
export interface HubSpotIntegrationConfig {
|
|
22
|
+
name: string;
|
|
23
|
+
dependencies: Record<string, string>;
|
|
24
|
+
devDependencies: Record<string, string>;
|
|
25
|
+
scripts: Record<string, string>;
|
|
26
|
+
additivePaths: string[];
|
|
27
|
+
mergeFiles: string[];
|
|
28
|
+
conditionalPaths: ConditionalPath[];
|
|
29
|
+
}
|
|
30
|
+
export declare const hubspotConfig: HubSpotIntegrationConfig;
|
|
31
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../../src/modules/features/forms/hubspot/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,QAAQ,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACpC;AAED,eAAO,MAAM,aAAa,EAAE,wBAoB3B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HubSpot integration configuration manifest.
|
|
3
|
+
* Single source of truth for dependencies, scripts, paths, and merge rules.
|
|
4
|
+
*
|
|
5
|
+
* The core is dependency-free: it loads HubSpot's official forms script at
|
|
6
|
+
* runtime and styles the injected DOM with self-contained CSS.
|
|
7
|
+
*/
|
|
8
|
+
export const hubspotConfig = {
|
|
9
|
+
name: "hubspot",
|
|
10
|
+
// The core embed loads HubSpot's script at runtime — no extra packages.
|
|
11
|
+
dependencies: {},
|
|
12
|
+
devDependencies: {},
|
|
13
|
+
scripts: {},
|
|
14
|
+
additivePaths: ["lib/integrations/hubspot"],
|
|
15
|
+
mergeFiles: [],
|
|
16
|
+
// The Sanity Studio picker is only useful with Sanity installed.
|
|
17
|
+
conditionalPaths: [
|
|
18
|
+
{
|
|
19
|
+
src: "_sanity-adapter",
|
|
20
|
+
dest: "lib/integrations/hubspot/sanity",
|
|
21
|
+
requires: "sanity",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../../src/modules/features/forms/hubspot/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,MAAM,CAAC,MAAM,aAAa,GAA6B;IACtD,IAAI,EAAE,SAAS;IAEf,wEAAwE;IACxE,YAAY,EAAE,EAAE;IAChB,eAAe,EAAE,EAAE;IACnB,OAAO,EAAE,EAAE;IAEX,aAAa,EAAE,CAAC,0BAA0B,CAAC;IAE3C,UAAU,EAAE,EAAE;IAEd,iEAAiE;IACjE,gBAAgB,EAAE;QACjB;YACC,GAAG,EAAE,iBAAiB;YACtB,IAAI,EAAE,iCAAiC;YACvC,QAAQ,EAAE,QAAQ;SAClB;KACD;CACD,CAAC"}
|
package/dist/paths.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export declare const TEMPLATES_DIR: string;
|
|
|
4
4
|
export declare const TEMPLATE_HOOKS_DIR: string;
|
|
5
5
|
/** Directory containing the Biome linting plugin rules. */
|
|
6
6
|
export declare const PLUGINS_DIR: string;
|
|
7
|
+
/** Directory containing bundled agent skills copied into generated projects. */
|
|
8
|
+
export declare const AGENT_SKILLS_DIR: string;
|
|
9
|
+
/** Node-version guard injected into each scaffolded project; under `src/` so it ships verbatim. */
|
|
10
|
+
export declare const CHECK_NODE_VERSION_FILE: string;
|
|
7
11
|
/**
|
|
8
12
|
* Directory containing the Sanity integration source files.
|
|
9
13
|
* Always resolves to `src/modules/features/cms/sanity/files/` relative to the
|
|
@@ -17,4 +21,16 @@ export declare const SANITY_FILES_DIR: string;
|
|
|
17
21
|
* relative to the project root.
|
|
18
22
|
*/
|
|
19
23
|
export declare const SANITY_PAGEBUILDER_FILES_DIR: string;
|
|
24
|
+
/**
|
|
25
|
+
* Directory containing the HubSpot integration source files.
|
|
26
|
+
* Always resolves to `src/modules/features/forms/hubspot/files/` relative to the
|
|
27
|
+
* project root.
|
|
28
|
+
*/
|
|
29
|
+
export declare const HUBSPOT_FILES_DIR: string;
|
|
30
|
+
/**
|
|
31
|
+
* Directory containing the dotenvx integration source files (the CI guard
|
|
32
|
+
* workflow and the 1Password key-restore script). Always resolves to
|
|
33
|
+
* `src/modules/features/env/dotenvx/files/` relative to the project root.
|
|
34
|
+
*/
|
|
35
|
+
export declare const DOTENVX_FILES_DIR: string;
|
|
20
36
|
//# sourceMappingURL=paths.d.ts.map
|
package/dist/paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAaA,6DAA6D;AAC7D,eAAO,MAAM,aAAa,EAAE,MAI3B,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,EAAE,MAIhC,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,WAAW,EAAE,MAA2C,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAQ9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAQ1C,CAAC"}
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAaA,6DAA6D;AAC7D,eAAO,MAAM,aAAa,EAAE,MAI3B,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,EAAE,MAIhC,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,WAAW,EAAE,MAA2C,CAAC;AAEtE,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,EAAE,MAI9B,CAAC;AAEF,mGAAmG;AACnG,eAAO,MAAM,uBAAuB,EAAE,MAKrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAQ9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAQ1C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAQ/B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAQ/B,CAAC"}
|
package/dist/paths.js
CHANGED
|
@@ -14,6 +14,10 @@ export const TEMPLATES_DIR = path.join(PROJECT_ROOT, "src", "templates");
|
|
|
14
14
|
export const TEMPLATE_HOOKS_DIR = path.join(PROJECT_ROOT, "src", "template-hooks");
|
|
15
15
|
/** Directory containing the Biome linting plugin rules. */
|
|
16
16
|
export const PLUGINS_DIR = path.join(PROJECT_ROOT, "plugins");
|
|
17
|
+
/** Directory containing bundled agent skills copied into generated projects. */
|
|
18
|
+
export const AGENT_SKILLS_DIR = path.join(PROJECT_ROOT, "src", "agent-skills");
|
|
19
|
+
/** Node-version guard injected into each scaffolded project; under `src/` so it ships verbatim. */
|
|
20
|
+
export const CHECK_NODE_VERSION_FILE = path.join(PROJECT_ROOT, "src", "assets", "check-node-version.mjs");
|
|
17
21
|
/**
|
|
18
22
|
* Directory containing the Sanity integration source files.
|
|
19
23
|
* Always resolves to `src/modules/features/cms/sanity/files/` relative to the
|
|
@@ -27,4 +31,16 @@ export const SANITY_FILES_DIR = path.join(PROJECT_ROOT, "src", "modules", "featu
|
|
|
27
31
|
* relative to the project root.
|
|
28
32
|
*/
|
|
29
33
|
export const SANITY_PAGEBUILDER_FILES_DIR = path.join(PROJECT_ROOT, "src", "modules", "features", "cms", "sanity-pagebuilder", "files");
|
|
34
|
+
/**
|
|
35
|
+
* Directory containing the HubSpot integration source files.
|
|
36
|
+
* Always resolves to `src/modules/features/forms/hubspot/files/` relative to the
|
|
37
|
+
* project root.
|
|
38
|
+
*/
|
|
39
|
+
export const HUBSPOT_FILES_DIR = path.join(PROJECT_ROOT, "src", "modules", "features", "forms", "hubspot", "files");
|
|
40
|
+
/**
|
|
41
|
+
* Directory containing the dotenvx integration source files (the CI guard
|
|
42
|
+
* workflow and the 1Password key-restore script). Always resolves to
|
|
43
|
+
* `src/modules/features/env/dotenvx/files/` relative to the project root.
|
|
44
|
+
*/
|
|
45
|
+
export const DOTENVX_FILES_DIR = path.join(PROJECT_ROOT, "src", "modules", "features", "env", "dotenvx", "files");
|
|
30
46
|
//# sourceMappingURL=paths.js.map
|
package/dist/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1D,MAAM,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAEnD;;;;GAIG;AACH,MAAM,YAAY,GAAW,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAW,IAAI,CAAC,IAAI,CAC7C,YAAY,EACZ,KAAK,EACL,WAAW,CACX,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,kBAAkB,GAAW,IAAI,CAAC,IAAI,CAClD,YAAY,EACZ,KAAK,EACL,gBAAgB,CAChB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAW,IAAI,CAAC,IAAI,CAChD,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,QAAQ,EACR,OAAO,CACP,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAW,IAAI,CAAC,IAAI,CAC5D,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,oBAAoB,EACpB,OAAO,CACP,CAAC"}
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1D,MAAM,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAEnD;;;;GAIG;AACH,MAAM,YAAY,GAAW,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAW,IAAI,CAAC,IAAI,CAC7C,YAAY,EACZ,KAAK,EACL,WAAW,CACX,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,kBAAkB,GAAW,IAAI,CAAC,IAAI,CAClD,YAAY,EACZ,KAAK,EACL,gBAAgB,CAChB,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAEtE,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAW,IAAI,CAAC,IAAI,CAChD,YAAY,EACZ,KAAK,EACL,cAAc,CACd,CAAC;AAEF,mGAAmG;AACnG,MAAM,CAAC,MAAM,uBAAuB,GAAW,IAAI,CAAC,IAAI,CACvD,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,wBAAwB,CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAW,IAAI,CAAC,IAAI,CAChD,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,QAAQ,EACR,OAAO,CACP,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAW,IAAI,CAAC,IAAI,CAC5D,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,oBAAoB,EACpB,OAAO,CACP,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAW,IAAI,CAAC,IAAI,CACjD,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,OAAO,EACP,SAAS,EACT,OAAO,CACP,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAW,IAAI,CAAC,IAAI,CACjD,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,KAAK,EACL,SAAS,EACT,OAAO,CACP,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bsmnt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"packageManager": "bun@1.
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"packageManager": "bun@1.3.14",
|
|
5
5
|
"description": "CLI to scaffold basement projects and add integrations",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=24"
|
|
9
|
+
},
|
|
7
10
|
"workspaces": [
|
|
8
11
|
".",
|
|
9
12
|
"src/templates/*"
|
|
@@ -20,12 +23,18 @@
|
|
|
20
23
|
"!src/templates/*/.next",
|
|
21
24
|
"!src/templates/*/bun.lock",
|
|
22
25
|
"src/template-hooks",
|
|
26
|
+
"src/agent-skills",
|
|
23
27
|
"src/modules/features/cms/sanity/files",
|
|
28
|
+
"src/modules/features/cms/sanity-pagebuilder/files",
|
|
29
|
+
"src/modules/features/env/dotenvx/files",
|
|
30
|
+
"src/assets",
|
|
24
31
|
"plugins"
|
|
25
32
|
],
|
|
26
33
|
"scripts": {
|
|
34
|
+
"preinstall": "node src/assets/check-node-version.mjs",
|
|
27
35
|
"build": "tsc",
|
|
28
36
|
"check": "tsc --noEmit",
|
|
37
|
+
"test": "bun test src",
|
|
29
38
|
"dev": "tsx src/index.ts",
|
|
30
39
|
"lint": "biome check .",
|
|
31
40
|
"lint:fix": "biome check --write --unsafe .",
|
|
@@ -51,7 +60,9 @@
|
|
|
51
60
|
"lint:all": "turbo run lint --filter=bsmnt-next-starter --filter=bsmnt-webgpu-starter --filter=bsmnt-experiments-starter",
|
|
52
61
|
"version-canary": "changeset version --snapshot canary",
|
|
53
62
|
"release-canary": "changeset publish --tag canary --no-git-tag",
|
|
54
|
-
"test:templates": "bash scripts/test-templates.sh"
|
|
63
|
+
"test:templates": "bash scripts/test-templates.sh",
|
|
64
|
+
"link:local": "bash scripts/build-and-link.sh",
|
|
65
|
+
"unlink:local": "bash scripts/build-and-link.sh --unlink"
|
|
55
66
|
},
|
|
56
67
|
"keywords": [
|
|
57
68
|
"webgpu",
|
|
@@ -63,23 +74,24 @@
|
|
|
63
74
|
"author": "",
|
|
64
75
|
"license": "ISC",
|
|
65
76
|
"dependencies": {
|
|
66
|
-
"@sanity/client": "^7.
|
|
67
|
-
"@sanity/image-url": "^2.
|
|
68
|
-
"@sanity/vision": "^5.
|
|
77
|
+
"@sanity/client": "^7.22.1",
|
|
78
|
+
"@sanity/image-url": "^2.1.1",
|
|
79
|
+
"@sanity/vision": "^5.30.0",
|
|
69
80
|
"commander": "^13.1.0",
|
|
81
|
+
"dotenv": "^17.4.2",
|
|
70
82
|
"fs-extra": "^11.3.3",
|
|
71
|
-
"next-sanity": "^
|
|
83
|
+
"next-sanity": "^13.0.10",
|
|
72
84
|
"ora": "^9.1.0",
|
|
73
85
|
"picocolors": "^1.1.1",
|
|
74
86
|
"prompts": "^2.4.2",
|
|
75
|
-
"sanity": "^5.
|
|
87
|
+
"sanity": "^5.30.0"
|
|
76
88
|
},
|
|
77
89
|
"devDependencies": {
|
|
78
90
|
"@biomejs/biome": "^2.4.14",
|
|
79
91
|
"@changesets/changelog-github": "^0.5.2",
|
|
80
92
|
"@changesets/cli": "^2.29.8",
|
|
81
93
|
"@types/fs-extra": "^11.0.4",
|
|
82
|
-
"@types/node": "^
|
|
94
|
+
"@types/node": "^24.13.1",
|
|
83
95
|
"@types/prompts": "^2.4.9",
|
|
84
96
|
"cross-env": "^10.1.0",
|
|
85
97
|
"lefthook": "^1.13.0",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: json-ld
|
|
3
|
+
description: >-
|
|
4
|
+
Add schema.org JSON-LD structured data when building components or pages
|
|
5
|
+
that render structured content (job listings, FAQs, events, videos,
|
|
6
|
+
work/product lists, articles, breadcrumbs). Use BEFORE hand-writing any
|
|
7
|
+
<script type="application/ld+json"> tag — this project ships typed
|
|
8
|
+
generators for all common schemas.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# JSON-LD Structured Data
|
|
12
|
+
|
|
13
|
+
This project ships typed JSON-LD generators and a `<JsonLd />` component in
|
|
14
|
+
`lib/utils/json-ld.tsx`. Never hand-roll a `<script type="application/ld+json">`
|
|
15
|
+
tag — import a generator and render it through `<JsonLd />` (it serializes and
|
|
16
|
+
escapes `<` for safe embedding).
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { JsonLd, generateJobPostingJsonLd } from "@/lib/utils/json-ld"
|
|
20
|
+
|
|
21
|
+
// inside a server component
|
|
22
|
+
{jobs.map((job) => (
|
|
23
|
+
<JsonLd
|
|
24
|
+
key={job.id}
|
|
25
|
+
data={generateJobPostingJsonLd({
|
|
26
|
+
title: job.title,
|
|
27
|
+
description: job.description,
|
|
28
|
+
datePosted: job.publishedAt,
|
|
29
|
+
employmentType: job.type,
|
|
30
|
+
organizationName: job.company,
|
|
31
|
+
})}
|
|
32
|
+
/>
|
|
33
|
+
))}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Which tier owns the data?
|
|
37
|
+
|
|
38
|
+
1. **Site-wide identity** (`Organization`, `WebSite`) — already emitted by the
|
|
39
|
+
site layout. Never re-emit these from components or pages. With Sanity,
|
|
40
|
+
editors manage it in Studio → Layout → Structured Data; Company Data social
|
|
41
|
+
links merge into `sameAs` via their "Include in Structured Data" toggle.
|
|
42
|
+
2. **Page-level** (Sanity projects only) — editors attach predefined JSON-LD
|
|
43
|
+
blocks (FAQ, Event, Video, Job Posting, Software Application, Item List,
|
|
44
|
+
Custom) to a page under SEO & Metadata → Structured Data (JSON-LD). The
|
|
45
|
+
page document component already renders them. If the content is page-owned
|
|
46
|
+
and editor-managed, point editors to that field instead of coding it.
|
|
47
|
+
3. **Component-level** — when a component itself renders structured content
|
|
48
|
+
(from props or CMS data), emit JSON-LD next to the markup using the
|
|
49
|
+
generators below.
|
|
50
|
+
|
|
51
|
+
## Component → schema mapping
|
|
52
|
+
|
|
53
|
+
| Component renders | Generator |
|
|
54
|
+
| ------------------------------------------ | ------------------------------------ |
|
|
55
|
+
| Job / career listings | `generateJobPostingJsonLd` (per job) |
|
|
56
|
+
| FAQ / accordion Q&A | `generateFaqJsonLd` |
|
|
57
|
+
| Events / agenda | `generateEventJsonLd` (per event) |
|
|
58
|
+
| Video player or embed | `generateVideoJsonLd` |
|
|
59
|
+
| Curated lists (work, products, post index) | `generateItemListJsonLd` |
|
|
60
|
+
| Article / blog post body | `generateArticleJsonLd` |
|
|
61
|
+
| Breadcrumb navigation | `generateBreadcrumbJsonLd` |
|
|
62
|
+
| App / tool promo section | `generateSoftwareApplicationJsonLd` |
|
|
63
|
+
| Plain marketing pages | `generateWebPageJsonLd` |
|
|
64
|
+
| Logo walls, testimonials, generic heroes | none — don't force structured data |
|
|
65
|
+
|
|
66
|
+
## Rules
|
|
67
|
+
|
|
68
|
+
- Emit from **server components** so the script tags are in the initial HTML.
|
|
69
|
+
- One `<JsonLd />` per entity — map each job/event to its own tag instead of
|
|
70
|
+
merging unrelated entities into one block.
|
|
71
|
+
- Only emit when the schema's required fields exist (e.g. `JobPosting` needs
|
|
72
|
+
title, description, datePosted). Skip the tag entirely rather than emitting
|
|
73
|
+
partial data.
|
|
74
|
+
- Sanity data: run values through `stegaClean` from `next-sanity` before they
|
|
75
|
+
reach JSON-LD (see `components/layout/json-ld` for the pattern), otherwise
|
|
76
|
+
invisible stega characters leak into the emitted markup.
|
|
77
|
+
- Don't duplicate: if a page-level Sanity block already covers the content,
|
|
78
|
+
don't also emit it from the component.
|
|
79
|
+
- Generators absolutize app-relative URLs (`/jobs/123`) automatically; pass
|
|
80
|
+
absolute URLs (including Sanity CDN assets) as-is.
|
|
81
|
+
|
|
82
|
+
## Verify
|
|
83
|
+
|
|
84
|
+
Check `view-source:` for each `application/ld+json` script and validate with
|
|
85
|
+
https://validator.schema.org or https://search.google.com/test/rich-results.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: manage-env
|
|
3
|
+
description: >-
|
|
4
|
+
Use when adding or changing an environment variable in a project that uses our
|
|
5
|
+
dotenvx setup. Decides secret vs trivial config: trivial/`NEXT_PUBLIC_*` the
|
|
6
|
+
agent handles fully, but for a secret the agent only wires the key in code
|
|
7
|
+
(process.env, validation schema, types) and hands the value-setting to the
|
|
8
|
+
human — it never types a secret value into a command. Triggers on "add an env
|
|
9
|
+
var", "new environment variable", "set an API key/token/secret", "put X in
|
|
10
|
+
.env", "encrypt env", or editing any `.env*` file.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Add or change an environment variable
|
|
14
|
+
|
|
15
|
+
This project uses **dotenvx**. Env files:
|
|
16
|
+
|
|
17
|
+
- `.env` — shared / development, committed **encrypted**
|
|
18
|
+
- `.env.preview`, `.env.production` — per-environment overrides, committed encrypted (created on demand)
|
|
19
|
+
- `.env.local` — plaintext, gitignored (personal local overrides)
|
|
20
|
+
- `.env.keys` — private keys, gitignored (backed up in the team password manager)
|
|
21
|
+
|
|
22
|
+
Scripts run `dotenvx run -f .env.$VERCEL_ENV -f .env -- …`, so the env-specific
|
|
23
|
+
file overrides `.env`. A **gitleaks** pre-commit hook + CI scan are the real
|
|
24
|
+
enforcement — this skill just makes the right choice the default.
|
|
25
|
+
|
|
26
|
+
## 1. Secret or trivial config?
|
|
27
|
+
|
|
28
|
+
- **Secret** — API keys, tokens, DB URLs, anything you'd rotate if it leaked.
|
|
29
|
+
- **Trivial** — public base URLs, feature flags, anything `NEXT_PUBLIC_*` (it
|
|
30
|
+
ships to the browser anyway). Plaintext is fine; encrypting buys nothing.
|
|
31
|
+
|
|
32
|
+
## 2a. Secret → never put the value in a command
|
|
33
|
+
|
|
34
|
+
A raw secret in a command (`env:set KEY <value>`) leaks the plaintext into the
|
|
35
|
+
tool call and the conversation context. So split the work:
|
|
36
|
+
|
|
37
|
+
- **Agent — code wiring only, never the value.** Read it via `process.env.KEY`,
|
|
38
|
+
add it to the env validation schema / types if the project has one, and add a
|
|
39
|
+
placeholder line to `.env.example`. Document the key name and where it's used.
|
|
40
|
+
- **Human — owns the value.** Either run `bun run env:set KEY <value>` yourself
|
|
41
|
+
(`--preview` / `--prod` for per-environment), or set it directly in the Vercel
|
|
42
|
+
environment. `env:set` encrypts in place and adds the matching
|
|
43
|
+
`DOTENV_PRIVATE_KEY*` to `.env.keys`.
|
|
44
|
+
- **Verify (agent):** only via `git diff` showing `KEY=encrypted:…`. Never run
|
|
45
|
+
`env:view` on a secret — it prints the decrypted value into context.
|
|
46
|
+
- Each `DOTENV_PRIVATE_KEY*` must exist on the matching Vercel environment and as a
|
|
47
|
+
CI secret, or it won't decrypt there.
|
|
48
|
+
- **Edge runtime caveat.** dotenvx only decrypts in the Node runtime (via
|
|
49
|
+
`instrumentation.ts`). A secret read in `middleware.ts` or a `runtime = "edge"`
|
|
50
|
+
route is **not** decrypted from `.env` — it must be set directly as a Vercel env
|
|
51
|
+
var. The encrypted `.env` covers Node functions + build, not the edge.
|
|
52
|
+
|
|
53
|
+
## 2b. Trivial config → plaintext
|
|
54
|
+
|
|
55
|
+
Add it plaintext — no encryption — with `bun run env:set KEY value --plain`, or
|
|
56
|
+
just append a line to the file:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
NEXT_PUBLIC_FOO=bar
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
gitleaks ignores non-secret plaintext, so it won't fail the scan.
|
|
63
|
+
|
|
64
|
+
## Rule
|
|
65
|
+
|
|
66
|
+
Never commit a real secret in plaintext. If one lands there, bulk-encrypt it in
|
|
67
|
+
place with `bun run env:encrypt-all` (no value typed).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Reads engines.node from cwd's package.json so one file works in this repo and
|
|
2
|
+
// every project it's injected into.
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
|
|
5
|
+
let required = Number.NaN;
|
|
6
|
+
try {
|
|
7
|
+
const { engines } = JSON.parse(readFileSync("package.json", "utf8"));
|
|
8
|
+
required = Number(engines?.node?.match(/\d+/)?.[0]);
|
|
9
|
+
} catch {
|
|
10
|
+
// Can't read or parse package.json — nothing to enforce, let install proceed.
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (
|
|
15
|
+
!Number.isNaN(required) &&
|
|
16
|
+
Number(process.versions.node.split(".")[0]) < required
|
|
17
|
+
) {
|
|
18
|
+
console.error(
|
|
19
|
+
`\nNode ${required}+ required. You have ${process.versions.node}.\n`,
|
|
20
|
+
);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
@@ -6,6 +6,9 @@ import {
|
|
|
6
6
|
ALL_ARTICLES_QUERY,
|
|
7
7
|
ARTICLE_QUERY,
|
|
8
8
|
} from "@/lib/integrations/sanity/queries";
|
|
9
|
+
import { urlForImage } from "@/lib/integrations/sanity/utils/image";
|
|
10
|
+
import { buildPageJsonLd } from "@/lib/integrations/sanity/utils/page-json-ld";
|
|
11
|
+
import { generateArticleJsonLd, JsonLd } from "@/lib/utils/json-ld";
|
|
9
12
|
|
|
10
13
|
export async function generateStaticParams() {
|
|
11
14
|
if (!client) return [];
|
|
@@ -30,28 +33,52 @@ export default async function BlogArticlePage({ params }: Props) {
|
|
|
30
33
|
|
|
31
34
|
if (!article) return notFound();
|
|
32
35
|
|
|
36
|
+
const articleUrl = `/blog/${slug}`;
|
|
37
|
+
const articleImage = article.featuredImage
|
|
38
|
+
? urlForImage(article.featuredImage).url()
|
|
39
|
+
: article.metadata?.image
|
|
40
|
+
? urlForImage(article.metadata.image).url()
|
|
41
|
+
: undefined;
|
|
42
|
+
const pageJsonLd = buildPageJsonLd(article.metadata?.jsonLd);
|
|
43
|
+
|
|
33
44
|
return (
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
<>
|
|
46
|
+
<JsonLd
|
|
47
|
+
data={generateArticleJsonLd({
|
|
48
|
+
title: article.metadata?.title || article.title || "",
|
|
49
|
+
url: articleUrl,
|
|
50
|
+
description: article.metadata?.description || article.excerpt,
|
|
51
|
+
image: articleImage,
|
|
52
|
+
datePublished: article.publishedAt,
|
|
53
|
+
dateModified: article._updatedAt,
|
|
54
|
+
authorName: article.author,
|
|
55
|
+
})}
|
|
56
|
+
/>
|
|
57
|
+
{pageJsonLd.map(({ key, data }) => (
|
|
58
|
+
<JsonLd key={key} data={data} />
|
|
59
|
+
))}
|
|
60
|
+
<article className="container mx-auto px-4 py-8 max-w-4xl">
|
|
61
|
+
<header className="mb-8">
|
|
62
|
+
<h1 className="text-4xl font-bold mb-4">{article.title}</h1>
|
|
63
|
+
{article.excerpt && (
|
|
64
|
+
<p className="text-lg text-gray-600">{article.excerpt}</p>
|
|
46
65
|
)}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
<div className="flex gap-4 mt-4 text-sm text-gray-500">
|
|
67
|
+
{article.author && <span>By {article.author}</span>}
|
|
68
|
+
{article.publishedAt && (
|
|
69
|
+
<time dateTime={article.publishedAt}>
|
|
70
|
+
{new Date(article.publishedAt).toLocaleDateString()}
|
|
71
|
+
</time>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
</header>
|
|
75
|
+
|
|
76
|
+
{article.content && (
|
|
77
|
+
<div className="prose max-w-none">
|
|
78
|
+
<RichText content={article.content} />
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</article>
|
|
82
|
+
</>
|
|
56
83
|
);
|
|
57
84
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { sanityFetch } from "@/lib/integrations/sanity/live";
|
|
3
|
+
import { ALL_ARTICLES_QUERY } from "@/lib/integrations/sanity/queries";
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
title: "Blog",
|
|
7
|
+
alternates: {
|
|
8
|
+
types: { "application/rss+xml": "/feed.xml" },
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default async function BlogIndexPage() {
|
|
13
|
+
const { data: articles } = await sanityFetch({ query: ALL_ARTICLES_QUERY });
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<main className="container mx-auto px-4 py-8 max-w-4xl">
|
|
17
|
+
<h1 className="text-4xl font-bold mb-8">Blog</h1>
|
|
18
|
+
|
|
19
|
+
{articles && articles.length > 0 ? (
|
|
20
|
+
<ul className="flex flex-col gap-8">
|
|
21
|
+
{articles.map((article) => {
|
|
22
|
+
const slug = article.slug?.current;
|
|
23
|
+
if (!slug) return null;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<li key={article._id}>
|
|
27
|
+
<article>
|
|
28
|
+
<h2 className="text-2xl font-semibold mb-2">
|
|
29
|
+
<Link href={`/blog/${slug}`} className="hover:underline">
|
|
30
|
+
{article.title}
|
|
31
|
+
</Link>
|
|
32
|
+
</h2>
|
|
33
|
+
{article.excerpt && (
|
|
34
|
+
<p className="text-gray-600 mb-2">{article.excerpt}</p>
|
|
35
|
+
)}
|
|
36
|
+
<div className="flex gap-4 text-sm text-gray-500">
|
|
37
|
+
{article.author && <span>By {article.author}</span>}
|
|
38
|
+
{article.publishedAt && (
|
|
39
|
+
<time dateTime={article.publishedAt}>
|
|
40
|
+
{new Date(article.publishedAt).toLocaleDateString()}
|
|
41
|
+
</time>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
</article>
|
|
45
|
+
</li>
|
|
46
|
+
);
|
|
47
|
+
})}
|
|
48
|
+
</ul>
|
|
49
|
+
) : (
|
|
50
|
+
<p className="text-gray-600">No articles published yet.</p>
|
|
51
|
+
)}
|
|
52
|
+
</main>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { client } from "@/lib/integrations/sanity/client";
|
|
2
|
+
import { ALL_ARTICLES_QUERY } from "@/lib/integrations/sanity/queries";
|
|
3
|
+
import { generateRssFeed, rssErrorResponse } from "@/lib/utils/rss";
|
|
4
|
+
import { getBaseUrl } from "@/lib/utils/url";
|
|
5
|
+
|
|
6
|
+
export const dynamic = "force-dynamic";
|
|
7
|
+
|
|
8
|
+
export async function GET() {
|
|
9
|
+
const baseUrl = getBaseUrl();
|
|
10
|
+
if (!client) return rssErrorResponse();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const articles = await client.fetch(ALL_ARTICLES_QUERY);
|
|
14
|
+
|
|
15
|
+
const items = (articles ?? [])
|
|
16
|
+
.filter((article) => article.slug?.current && !article.metadata?.noIndex)
|
|
17
|
+
.map((article) => ({
|
|
18
|
+
title: article.title ?? "Untitled",
|
|
19
|
+
link: `${baseUrl}/blog/${article.slug?.current}`,
|
|
20
|
+
description: article.excerpt ?? undefined,
|
|
21
|
+
pubDate: article.publishedAt ?? undefined,
|
|
22
|
+
authors: article.author ? [article.author] : undefined,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
return generateRssFeed({
|
|
26
|
+
title: `${new URL(baseUrl).hostname} Blog`,
|
|
27
|
+
link: `${baseUrl}/blog`,
|
|
28
|
+
description: "Latest articles",
|
|
29
|
+
feedUrl: `${baseUrl}/feed.xml`,
|
|
30
|
+
items,
|
|
31
|
+
});
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error("Error generating RSS feed:", error);
|
|
34
|
+
return rssErrorResponse();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { stegaClean } from "next-sanity";
|
|
2
|
+
import { sanityFetch } from "@/lib/integrations/sanity/live";
|
|
3
|
+
import { STRUCTURED_DATA_QUERY } from "@/lib/integrations/sanity/queries";
|
|
4
|
+
import {
|
|
5
|
+
generateOrganizationJsonLd,
|
|
6
|
+
generateWebSiteJsonLd,
|
|
7
|
+
JsonLd,
|
|
8
|
+
} from "@/lib/utils/json-ld";
|
|
9
|
+
|
|
10
|
+
type StructuredDataResult = {
|
|
11
|
+
name?: string | null;
|
|
12
|
+
legalName?: string | null;
|
|
13
|
+
description?: string | null;
|
|
14
|
+
url?: string | null;
|
|
15
|
+
logo?: string | null;
|
|
16
|
+
sameAs?: (string | null)[] | null;
|
|
17
|
+
contactPoint?: {
|
|
18
|
+
email?: string | null;
|
|
19
|
+
telephone?: string | null;
|
|
20
|
+
contactType?: string | null;
|
|
21
|
+
} | null;
|
|
22
|
+
address?: {
|
|
23
|
+
streetAddress?: string | null;
|
|
24
|
+
locality?: string | null;
|
|
25
|
+
region?: string | null;
|
|
26
|
+
postalCode?: string | null;
|
|
27
|
+
country?: string | null;
|
|
28
|
+
} | null;
|
|
29
|
+
} | null;
|
|
30
|
+
|
|
31
|
+
const nonEmpty = (value: unknown): string | undefined => {
|
|
32
|
+
const cleaned = stegaClean(value);
|
|
33
|
+
return typeof cleaned === "string" && cleaned.trim() !== ""
|
|
34
|
+
? cleaned
|
|
35
|
+
: undefined;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Site-wide Organization + WebSite JSON-LD from the Structured Data
|
|
40
|
+
* singleton, with the static app values as fallback.
|
|
41
|
+
*/
|
|
42
|
+
export async function SanityStructuredData({
|
|
43
|
+
fallbackName,
|
|
44
|
+
fallbackDescription,
|
|
45
|
+
fallbackLogo,
|
|
46
|
+
}: {
|
|
47
|
+
fallbackName: string;
|
|
48
|
+
fallbackDescription?: string;
|
|
49
|
+
fallbackLogo?: string;
|
|
50
|
+
}) {
|
|
51
|
+
const { data } = await sanityFetch({ query: STRUCTURED_DATA_QUERY });
|
|
52
|
+
// Deep-clean stega artifacts up front so nested objects (contactPoint,
|
|
53
|
+
// address) never leak visual-editing markers into the emitted JSON-LD.
|
|
54
|
+
const structuredData = stegaClean(data as unknown as StructuredDataResult);
|
|
55
|
+
|
|
56
|
+
const name = nonEmpty(structuredData?.name) ?? fallbackName;
|
|
57
|
+
const description =
|
|
58
|
+
nonEmpty(structuredData?.description) ?? fallbackDescription;
|
|
59
|
+
const url = nonEmpty(structuredData?.url);
|
|
60
|
+
const logo = nonEmpty(structuredData?.logo) ?? fallbackLogo;
|
|
61
|
+
|
|
62
|
+
const sameAs = (structuredData?.sameAs ?? [])
|
|
63
|
+
.map(nonEmpty)
|
|
64
|
+
.filter((value): value is string => Boolean(value));
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<JsonLd data={generateWebSiteJsonLd({ name, url, description })} />
|
|
69
|
+
<JsonLd
|
|
70
|
+
data={generateOrganizationJsonLd({
|
|
71
|
+
name,
|
|
72
|
+
url,
|
|
73
|
+
logo,
|
|
74
|
+
description,
|
|
75
|
+
legalName: nonEmpty(structuredData?.legalName),
|
|
76
|
+
sameAs: sameAs.length ? sameAs : undefined,
|
|
77
|
+
contactPoint: structuredData?.contactPoint,
|
|
78
|
+
address: structuredData?.address,
|
|
79
|
+
})}
|
|
80
|
+
/>
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
}
|