create-ailk 0.1.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/LICENSE +201 -0
- package/README.md +39 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +80 -0
- package/dist/copy.d.ts +8 -0
- package/dist/copy.js +109 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/lib/pro-callout.d.ts +12 -0
- package/dist/lib/pro-callout.js +20 -0
- package/dist/parse-args.d.ts +13 -0
- package/dist/parse-args.js +81 -0
- package/dist/programmatic.d.ts +49 -0
- package/dist/programmatic.js +89 -0
- package/dist/substitute.d.ts +31 -0
- package/dist/substitute.js +45 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.js +70 -0
- package/package.json +47 -0
- package/templates/.claude/.gitkeep +0 -0
- package/templates/.claude/agents/web.md +80 -0
- package/templates/.claude/rules/architecture.md +62 -0
- package/templates/.claude/rules/preserve-existing-style.md +51 -0
- package/templates/.claude/skills/README.md +43 -0
- package/templates/.claude/skills/add-schema/SKILL.md +270 -0
- package/templates/.claude/skills/add-schema/references/conflict-handling.md +200 -0
- package/templates/.claude/skills/add-schema/references/file-finding.md +123 -0
- package/templates/.claude/skills/add-schema/references/schema-types.md +131 -0
- package/templates/.claude/skills/audit-site/SKILL.md +213 -0
- package/templates/.claude/skills/audit-site/references/common-errors.md +113 -0
- package/templates/.claude/skills/audit-site/references/findings-glossary.md +138 -0
- package/templates/.claude/skills/audit-site/references/severity-levels.md +114 -0
- package/templates/.claude/skills/provision-config/SKILL.md +243 -0
- package/templates/.claude/skills/provision-config/references/env-vars-template.md +184 -0
- package/templates/.claude/skills/provision-config/references/runbook-template.md +248 -0
- package/templates/.claude/skills/provision-config/references/vercel-json-template.md +98 -0
- package/templates/.claude/skills/scaffold-auth/SKILL.md +261 -0
- package/templates/.claude/skills/scaffold-auth/references/env-vars.md +91 -0
- package/templates/.claude/skills/scaffold-auth/references/oauth-app-setup.md +171 -0
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +310 -0
- package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +71 -0
- package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +83 -0
- package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +72 -0
- package/templates/.claude/skills/scaffold-page/SKILL.md +243 -0
- package/templates/.claude/skills/scaffold-page/references/page-types.md +169 -0
- package/templates/.claude/skills/scaffold-page/templates/content.mdx.tmpl +28 -0
- package/templates/.claude/skills/scaffold-page/templates/route.tsx.tmpl +28 -0
- package/templates/.claude/skills/suggest-site-pages/SKILL.md +242 -0
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +287 -0
- package/templates/.env.example +205 -0
- package/templates/.gitkeep +2 -0
- package/templates/CLAUDE.md +142 -0
- package/templates/CONVENTIONS.md +222 -0
- package/templates/README.md +110 -0
- package/templates/apps/api/.env.example +40 -0
- package/templates/apps/api/CLAUDE.md +63 -0
- package/templates/apps/api/api/index.ts +144 -0
- package/templates/apps/api/jest.config.cjs +74 -0
- package/templates/apps/api/package.json +54 -0
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +138 -0
- package/templates/apps/api/src/__tests__/factories/index.ts +70 -0
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +82 -0
- package/templates/apps/api/src/__tests__/index.test.ts +118 -0
- package/templates/apps/api/src/__tests__/server.test.ts +207 -0
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +126 -0
- package/templates/apps/api/src/__tests__/setup.ts +24 -0
- package/templates/apps/api/src/cli.ts +30 -0
- package/templates/apps/api/src/config/__tests__/index.test.ts +97 -0
- package/templates/apps/api/src/config/index.ts +56 -0
- package/templates/apps/api/src/index.ts +32 -0
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +15 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +45 -0
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +178 -0
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +100 -0
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +94 -0
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +144 -0
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +8 -0
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +227 -0
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +125 -0
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +165 -0
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +129 -0
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +74 -0
- package/templates/apps/api/src/lib/content-adapter.ts +86 -0
- package/templates/apps/api/src/lib/error-serializer.ts +77 -0
- package/templates/apps/api/src/lib/errors.ts +95 -0
- package/templates/apps/api/src/lib/file-fallback.ts +87 -0
- package/templates/apps/api/src/lib/lead-capture-store.ts +110 -0
- package/templates/apps/api/src/lib/locales.ts +201 -0
- package/templates/apps/api/src/lib/outbound-http.ts +122 -0
- package/templates/apps/api/src/lib/prisma.ts +21 -0
- package/templates/apps/api/src/lib/require-paid-tier.ts +53 -0
- package/templates/apps/api/src/lib/stripe.ts +30 -0
- package/templates/apps/api/src/lib/webhook-idempotency.ts +92 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +111 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +172 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +119 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +138 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +149 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +139 -0
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +175 -0
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +76 -0
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +153 -0
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +72 -0
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +292 -0
- package/templates/apps/api/src/middleware/auth.ts +246 -0
- package/templates/apps/api/src/middleware/rate-limit.ts +132 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +129 -0
- package/templates/apps/api/src/openapi/index.ts +12 -0
- package/templates/apps/api/src/openapi/spec.ts +408 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +193 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +201 -0
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +294 -0
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +486 -0
- package/templates/apps/api/src/routes/auth/tokens.ts +199 -0
- package/templates/apps/api/src/routes/auth/user.ts +244 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +588 -0
- package/templates/apps/api/src/routes/checkout/index.ts +13 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +185 -0
- package/templates/apps/api/src/routes/content/__tests__/create.test.ts +239 -0
- package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +201 -0
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +141 -0
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +122 -0
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +44 -0
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +118 -0
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +51 -0
- package/templates/apps/api/src/routes/content/__tests__/update.test.ts +252 -0
- package/templates/apps/api/src/routes/content/create.ts +114 -0
- package/templates/apps/api/src/routes/content/delete.ts +81 -0
- package/templates/apps/api/src/routes/content/get-page.ts +98 -0
- package/templates/apps/api/src/routes/content/index.ts +32 -0
- package/templates/apps/api/src/routes/content/list-pages.ts +83 -0
- package/templates/apps/api/src/routes/content/list-types.ts +19 -0
- package/templates/apps/api/src/routes/content/rate-limit.ts +13 -0
- package/templates/apps/api/src/routes/content/slug.ts +9 -0
- package/templates/apps/api/src/routes/content/update.ts +111 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +415 -0
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +165 -0
- package/templates/apps/api/src/routes/leads/index.ts +130 -0
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +296 -0
- package/templates/apps/api/src/routes/test/auth/session.ts +141 -0
- package/templates/apps/api/src/routes/webhooks/README.md +57 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +247 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +198 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +633 -0
- package/templates/apps/api/src/routes/webhooks/index.ts +41 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +253 -0
- package/templates/apps/api/src/server.ts +157 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +395 -0
- package/templates/apps/api/src/services/enrichment-shim.ts +53 -0
- package/templates/apps/api/src/services/lead-routing.ts +338 -0
- package/templates/apps/api/tsconfig.json +34 -0
- package/templates/apps/api/vercel.json +17 -0
- package/templates/apps/mcp/.env.example +52 -0
- package/templates/apps/mcp/CLAUDE.md +84 -0
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +52 -0
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +46 -0
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +36 -0
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +54 -0
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +110 -0
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +213 -0
- package/templates/apps/mcp/__tests__/audit.test.ts +217 -0
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +52 -0
- package/templates/apps/mcp/__tests__/create_page.test.ts +201 -0
- package/templates/apps/mcp/__tests__/delete_page.test.ts +176 -0
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +82 -0
- package/templates/apps/mcp/__tests__/get_faq.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_locations.test.ts +65 -0
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +90 -0
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +80 -0
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +81 -0
- package/templates/apps/mcp/__tests__/http-transport.test.ts +323 -0
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +75 -0
- package/templates/apps/mcp/__tests__/lib/require-paid-tier.test.ts +75 -0
- package/templates/apps/mcp/__tests__/list_pages.test.ts +112 -0
- package/templates/apps/mcp/__tests__/locale.test.ts +135 -0
- package/templates/apps/mcp/__tests__/parity.test.ts +205 -0
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +34 -0
- package/templates/apps/mcp/__tests__/read_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/request_callback.test.ts +163 -0
- package/templates/apps/mcp/__tests__/search_content.test.ts +153 -0
- package/templates/apps/mcp/__tests__/server.test.ts +115 -0
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +165 -0
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +161 -0
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +227 -0
- package/templates/apps/mcp/__tests__/tools/scaffold.test.ts +237 -0
- package/templates/apps/mcp/__tests__/update_page.test.ts +195 -0
- package/templates/apps/mcp/jest.config.cjs +82 -0
- package/templates/apps/mcp/package.json +37 -0
- package/templates/apps/mcp/src/abuse/daily-cap.ts +47 -0
- package/templates/apps/mcp/src/abuse/email-validator.ts +25 -0
- package/templates/apps/mcp/src/abuse/honeypot.ts +21 -0
- package/templates/apps/mcp/src/abuse/index.ts +111 -0
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +58 -0
- package/templates/apps/mcp/src/http-transport.ts +303 -0
- package/templates/apps/mcp/src/index.ts +67 -0
- package/templates/apps/mcp/src/lib/audit-single-page.ts +194 -0
- package/templates/apps/mcp/src/lib/errors.ts +61 -0
- package/templates/apps/mcp/src/lib/locales.ts +171 -0
- package/templates/apps/mcp/src/lib/require-paid-tier.ts +44 -0
- package/templates/apps/mcp/src/lib/resolve-locale.ts +30 -0
- package/templates/apps/mcp/src/server.ts +139 -0
- package/templates/apps/mcp/src/tools/audit.ts +103 -0
- package/templates/apps/mcp/src/tools/capture_lead.ts +52 -0
- package/templates/apps/mcp/src/tools/create_page.ts +95 -0
- package/templates/apps/mcp/src/tools/delete_page.ts +73 -0
- package/templates/apps/mcp/src/tools/get_business_hours.ts +66 -0
- package/templates/apps/mcp/src/tools/get_faq.ts +69 -0
- package/templates/apps/mcp/src/tools/get_locations.ts +85 -0
- package/templates/apps/mcp/src/tools/get_offerings.ts +66 -0
- package/templates/apps/mcp/src/tools/get_pricing.ts +74 -0
- package/templates/apps/mcp/src/tools/get_site_info.ts +84 -0
- package/templates/apps/mcp/src/tools/index.ts +125 -0
- package/templates/apps/mcp/src/tools/list_pages.ts +72 -0
- package/templates/apps/mcp/src/tools/purchase.ts +89 -0
- package/templates/apps/mcp/src/tools/read_content.ts +61 -0
- package/templates/apps/mcp/src/tools/request_callback.ts +51 -0
- package/templates/apps/mcp/src/tools/scaffold.ts +119 -0
- package/templates/apps/mcp/src/tools/search_content.ts +59 -0
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +47 -0
- package/templates/apps/mcp/src/tools/update_page.ts +91 -0
- package/templates/apps/mcp/tsconfig.json +19 -0
- package/templates/apps/web/.env.example +47 -0
- package/templates/apps/web/CLAUDE.md +81 -0
- package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +94 -0
- package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +75 -0
- package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +82 -0
- package/templates/apps/web/__tests__/auth/env-helpers.test.ts +168 -0
- package/templates/apps/web/__tests__/authority-list-routes.test.tsx +208 -0
- package/templates/apps/web/__tests__/better-stack.test.ts +66 -0
- package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +87 -0
- package/templates/apps/web/__tests__/blog-source-populated.test.ts +130 -0
- package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +60 -0
- package/templates/apps/web/__tests__/google-analytics.test.tsx +104 -0
- package/templates/apps/web/__tests__/i18n/middleware.test.ts +119 -0
- package/templates/apps/web/__tests__/i18n/routing.test.ts +114 -0
- package/templates/apps/web/__tests__/i18n/translations.test.ts +191 -0
- package/templates/apps/web/__tests__/json-ld.test.ts +98 -0
- package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +580 -0
- package/templates/apps/web/__tests__/layout-stealth.test.ts +39 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +103 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +114 -0
- package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +94 -0
- package/templates/apps/web/__tests__/page.test.tsx +230 -0
- package/templates/apps/web/__tests__/products-services-phase1.test.tsx +321 -0
- package/templates/apps/web/__tests__/projects-routes.test.tsx +392 -0
- package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +475 -0
- package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +53 -0
- package/templates/apps/web/__tests__/routes/blog-route.test.tsx +191 -0
- package/templates/apps/web/__tests__/routes/llms-txt.test.ts +123 -0
- package/templates/apps/web/__tests__/routes/robots-txt.test.ts +52 -0
- package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +78 -0
- package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +203 -0
- package/templates/apps/web/__tests__/section-routes.test.tsx +693 -0
- package/templates/apps/web/__tests__/security-headers.test.ts +201 -0
- package/templates/apps/web/__tests__/sentry-config.test.ts +116 -0
- package/templates/apps/web/__tests__/setup.ts +82 -0
- package/templates/apps/web/__tests__/sitemap-locales.test.ts +415 -0
- package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +844 -0
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +81 -0
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +110 -0
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +58 -0
- package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +120 -0
- package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +202 -0
- package/templates/apps/web/app/[locale]/about/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +173 -0
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +45 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/careers/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/case-studies/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/clients/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +130 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +152 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +92 -0
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +79 -0
- package/templates/apps/web/app/[locale]/contact/error.tsx +24 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +38 -0
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +119 -0
- package/templates/apps/web/app/[locale]/courses/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +160 -0
- package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +25 -0
- package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +117 -0
- package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +58 -0
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +118 -0
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +72 -0
- package/templates/apps/web/app/[locale]/downloads/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +47 -0
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +130 -0
- package/templates/apps/web/app/[locale]/events/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/faq/page.tsx +36 -0
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +78 -0
- package/templates/apps/web/app/[locale]/how-to/page.tsx +40 -0
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/integrations/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/launch-service/page.tsx +31 -0
- package/templates/apps/web/app/[locale]/layout.tsx +241 -0
- package/templates/apps/web/app/[locale]/page.tsx +41 -0
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +44 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +113 -0
- package/templates/apps/web/app/[locale]/partners/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/products/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +138 -0
- package/templates/apps/web/app/[locale]/projects/page.tsx +30 -0
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +51 -0
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/resources/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +43 -0
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +129 -0
- package/templates/apps/web/app/[locale]/services/page.tsx +25 -0
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +81 -0
- package/templates/apps/web/app/[locale]/software/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/tech-articles/page.tsx +39 -0
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/testimonials/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +63 -0
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +27 -0
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +34 -0
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +82 -0
- package/templates/apps/web/app/[locale]/whitepapers/page.tsx +39 -0
- package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +152 -0
- package/templates/apps/web/app/api/auth/[...all]/route.ts +16 -0
- package/templates/apps/web/app/error-fallback.tsx +75 -0
- package/templates/apps/web/app/error.tsx +23 -0
- package/templates/apps/web/app/layout.tsx +18 -0
- package/templates/apps/web/app/llms.txt/route.ts +101 -0
- package/templates/apps/web/app/not-found.tsx +48 -0
- package/templates/apps/web/app/og/__tests__/route.test.ts +164 -0
- package/templates/apps/web/app/og/route.tsx +135 -0
- package/templates/apps/web/app/robots.txt/route.ts +36 -0
- package/templates/apps/web/app/sitemap.xml/route.ts +146 -0
- package/templates/apps/web/auth.ts +141 -0
- package/templates/apps/web/components/ThemeToggle.tsx +60 -0
- package/templates/apps/web/components/google-analytics.tsx +34 -0
- package/templates/apps/web/content/en/blog/index.mdx +15 -0
- package/templates/apps/web/content/en/blog/launching-ailk.mdx +20 -0
- package/templates/apps/web/content/en/docs/getting-started.mdx +30 -0
- package/templates/apps/web/i18n/request.ts +36 -0
- package/templates/apps/web/jest.config.cjs +100 -0
- package/templates/apps/web/lib/__mocks__/next-mdx-remote-rsc.js +12 -0
- package/templates/apps/web/lib/__mocks__/source-server.js +31 -0
- package/templates/apps/web/lib/__tests__/og.test.ts +65 -0
- package/templates/apps/web/lib/auth-env.ts +66 -0
- package/templates/apps/web/lib/blog-list-data.ts +95 -0
- package/templates/apps/web/lib/blog-post-data.ts +79 -0
- package/templates/apps/web/lib/nav-config.ts +13 -0
- package/templates/apps/web/lib/observability/better-stack.ts +27 -0
- package/templates/apps/web/lib/og.ts +23 -0
- package/templates/apps/web/lib/prisma-for-auth.ts +34 -0
- package/templates/apps/web/lib/source.ts +34 -0
- package/templates/apps/web/messages/en.json +131 -0
- package/templates/apps/web/middleware.ts +80 -0
- package/templates/apps/web/next.config.mjs +167 -0
- package/templates/apps/web/package.json +62 -0
- package/templates/apps/web/public/.well-known/security.txt +17 -0
- package/templates/apps/web/public/android-chrome-192x192.png +0 -0
- package/templates/apps/web/public/android-chrome-512x512.png +0 -0
- package/templates/apps/web/public/apple-touch-icon.png +0 -0
- package/templates/apps/web/public/favicon-16x16.png +0 -0
- package/templates/apps/web/public/favicon-32x32.png +0 -0
- package/templates/apps/web/public/favicon.ico +0 -0
- package/templates/apps/web/public/favicon.svg +4 -0
- package/templates/apps/web/public/logo-dark.svg +21 -0
- package/templates/apps/web/public/logo-light.svg +21 -0
- package/templates/apps/web/public/logomark-dark.svg +4 -0
- package/templates/apps/web/public/logomark-light.svg +4 -0
- package/templates/apps/web/public/og-default.png +0 -0
- package/templates/apps/web/public/site.webmanifest +19 -0
- package/templates/apps/web/scripts/assert-content-bundled.ts +55 -0
- package/templates/apps/web/security-headers.config.ts +132 -0
- package/templates/apps/web/sentry.client.config.ts +27 -0
- package/templates/apps/web/sentry.edge.config.ts +15 -0
- package/templates/apps/web/sentry.server.config.ts +20 -0
- package/templates/apps/web/source.config.ts +78 -0
- package/templates/apps/web/src/components/SiteNav.tsx +21 -0
- package/templates/apps/web/src/lib/routes.ts +37 -0
- package/templates/apps/web/tsconfig.json +35 -0
- package/templates/apps/web/types/messages.d.ts +19 -0
- package/templates/content/.gitkeep +0 -0
- package/templates/content/CLAUDE.md +85 -0
- package/templates/content/_site.mdx +38 -0
- package/templates/content/ar/HomePage/home.mdx +123 -0
- package/templates/content/ar/_site.mdx +35 -0
- package/templates/content/de/_site.mdx +29 -0
- package/templates/content/en/.gitkeep +0 -0
- package/templates/content/en/AboutPage/about.mdx +19 -0
- package/templates/content/en/AboutPage/about.schema.json +82 -0
- package/templates/content/en/BookCall/book-call.mdx +19 -0
- package/templates/content/en/BookCall/book-call.schema.json +121 -0
- package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +20 -0
- package/templates/content/en/CareersList/careers.mdx +24 -0
- package/templates/content/en/CaseStudiesList/case-studies.mdx +22 -0
- package/templates/content/en/CaseStudiesList/showcase.mdx +8 -0
- package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +32 -0
- package/templates/content/en/CaseStudy/schema-builder-migration.mdx +41 -0
- package/templates/content/en/ClientsList/clients.mdx +38 -0
- package/templates/content/en/ContactPage/contact.mdx +19 -0
- package/templates/content/en/ContactPage/contact.schema.json +100 -0
- package/templates/content/en/ContactPoint/primary.mdx +14 -0
- package/templates/content/en/Course/aeo-fundamentals.mdx +37 -0
- package/templates/content/en/Course/schema-builder-workshop.mdx +62 -0
- package/templates/content/en/CoursesList/courses.mdx +22 -0
- package/templates/content/en/DownloadsList/downloads.mdx +22 -0
- package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +39 -0
- package/templates/content/en/Event/ailk-launch-day-2026.mdx +35 -0
- package/templates/content/en/EventsList/events.mdx +26 -0
- package/templates/content/en/FAQPage/faq.mdx +420 -0
- package/templates/content/en/FAQPage/faq.schema.json +231 -0
- package/templates/content/en/GlossaryList/glossary.mdx +19 -0
- package/templates/content/en/GlossaryList/glossary.schema.json +300 -0
- package/templates/content/en/HomePage/home.mdx +312 -0
- package/templates/content/en/HomePage/home.schema.json +88 -0
- package/templates/content/en/HomePage/launch-service.mdx +475 -0
- package/templates/content/en/HomePage/launch-service.schema.json +138 -0
- package/templates/content/en/HowTo/add-mdx-content.mdx +38 -0
- package/templates/content/en/HowTo/configure-aeo-scoring.mdx +35 -0
- package/templates/content/en/HowTo/set-up-json-ld.mdx +36 -0
- package/templates/content/en/Integration/github-actions.mdx +31 -0
- package/templates/content/en/Integration/openai-api.mdx +26 -0
- package/templates/content/en/Integration/vercel.mdx +32 -0
- package/templates/content/en/IntegrationsList/integrations.mdx +22 -0
- package/templates/content/en/JobPosting/content-strategist.mdx +46 -0
- package/templates/content/en/JobPosting/developer-advocate.mdx +47 -0
- package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +57 -0
- package/templates/content/en/LandingPage/aeo-audit.mdx +19 -0
- package/templates/content/en/LandingPage/aeo-audit.schema.json +92 -0
- package/templates/content/en/LandingPage/agency-waitlist.mdx +340 -0
- package/templates/content/en/LandingPage/agency-waitlist.schema.json +152 -0
- package/templates/content/en/LandingPage/developers.mdx +19 -0
- package/templates/content/en/LandingPage/developers.schema.json +109 -0
- package/templates/content/en/LandingPage/for-agencies.mdx +390 -0
- package/templates/content/en/LandingPage/for-agencies.schema.json +107 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +417 -0
- package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +105 -0
- package/templates/content/en/LandingPage/for-businesses.mdx +19 -0
- package/templates/content/en/LandingPage/for-businesses.schema.json +96 -0
- package/templates/content/en/LandingPage/platform.mdx +369 -0
- package/templates/content/en/LandingPage/platform.schema.json +166 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +19 -0
- package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +102 -0
- package/templates/content/en/LandingPage/vs-wordpress.mdx +19 -0
- package/templates/content/en/LandingPage/vs-wordpress.schema.json +53 -0
- package/templates/content/en/NewsletterSignup/newsletter.mdx +236 -0
- package/templates/content/en/NewsletterSignup/newsletter.schema.json +91 -0
- package/templates/content/en/Organization/site-owner.mdx +16 -0
- package/templates/content/en/Partner/prisma.mdx +31 -0
- package/templates/content/en/Partner/supabase.mdx +30 -0
- package/templates/content/en/Partner/vercel.mdx +28 -0
- package/templates/content/en/PartnersList/partners.mdx +22 -0
- package/templates/content/en/Person/founder.mdx +18 -0
- package/templates/content/en/Pricing/pricing.mdx +538 -0
- package/templates/content/en/Pricing/pricing.schema.json +209 -0
- package/templates/content/en/PrivacyPage/privacy.mdx +165 -0
- package/templates/content/en/PrivacyPage/privacy.schema.json +64 -0
- package/templates/content/en/Product/ailk.mdx +19 -0
- package/templates/content/en/Product/ailk.schema.json +94 -0
- package/templates/content/en/Product/api-launch-kit.mdx +26 -0
- package/templates/content/en/Product/launch-kit.mdx +28 -0
- package/templates/content/en/ProductsList/products.mdx +26 -0
- package/templates/content/en/Project/ailk-phase-2.mdx +54 -0
- package/templates/content/en/ProjectsList/projects.mdx +25 -0
- package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +27 -0
- package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +28 -0
- package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +39 -0
- package/templates/content/en/ResourcesHub/resources.mdx +22 -0
- package/templates/content/en/Service/consulting.mdx +22 -0
- package/templates/content/en/Service/implementation.mdx +30 -0
- package/templates/content/en/Service/launch-service.mdx +232 -0
- package/templates/content/en/Service/launch.mdx +228 -0
- package/templates/content/en/ServicesList/services.mdx +84 -0
- package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +44 -0
- package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +47 -0
- package/templates/content/en/SoftwareProduct/ailk-schema.mdx +49 -0
- package/templates/content/en/TeamList/team.mdx +63 -0
- package/templates/content/en/TeamMember/founder.mdx +72 -0
- package/templates/content/en/TermsPage/terms.mdx +19 -0
- package/templates/content/en/TermsPage/terms.schema.json +99 -0
- package/templates/content/en/TestimonialsList/testimonials.mdx +44 -0
- package/templates/content/en/UseCasesList/use-cases.mdx +30 -0
- package/templates/content/en/Whitepaper/ax-first-product-development.mdx +27 -0
- package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +27 -0
- package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +31 -0
- package/templates/content/en-XA/AboutPage/about.mdx +8 -0
- package/templates/content/en-XA/FAQPage/faq.mdx +8 -0
- package/templates/content/en-XA/HomePage/home.mdx +8 -0
- package/templates/content/es/_site.mdx +30 -0
- package/templates/content/fr/_site.mdx +30 -0
- package/templates/content/ja/_site.mdx +30 -0
- package/templates/content/pt-BR/AboutPage/about.mdx +8 -0
- package/templates/content/pt-BR/FAQPage/faq.mdx +8 -0
- package/templates/content/pt-BR/HomePage/home.mdx +23 -0
- package/templates/database/CHANGELOG.md +5 -0
- package/templates/database/README.md +234 -0
- package/templates/database/__tests__/user-cascade.test.ts +125 -0
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +3 -0
- package/templates/database/inbox/__tests__/schema.test.ts +40 -0
- package/templates/database/inbox/schema.prisma +52 -0
- package/templates/database/jest.config.cjs +29 -0
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +328 -0
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +100 -0
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +28 -0
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +25 -0
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +42 -0
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +67 -0
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +21 -0
- package/templates/database/migrations/migration_lock.toml +3 -0
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/package.json +45 -0
- package/templates/database/prisma.config.ts +20 -0
- package/templates/database/schema.prisma +487 -0
- package/templates/database/scripts/db-generate-locked.sh +80 -0
- package/templates/database/seed-test.ts +85 -0
- package/templates/database/tsconfig.build.json +16 -0
- package/templates/database/tsconfig.json +9 -0
- package/templates/package.json +125 -0
- package/templates/pnpm-workspace.yaml +6 -0
- package/templates/project.yaml +59 -0
- package/templates/tsconfig.base.json +18 -0
- package/templates/tsconfig.json +45 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Mirrors apps/api's ts-jest setup (CONVENTIONS.md mentions Vitest aspirationally,
|
|
2
|
+
// but no Vitest is installed anywhere yet). JSDOM env so RTL can mount components.
|
|
3
|
+
module.exports = {
|
|
4
|
+
preset: "ts-jest",
|
|
5
|
+
testEnvironment: "jsdom",
|
|
6
|
+
roots: [
|
|
7
|
+
"<rootDir>/__tests__",
|
|
8
|
+
"<rootDir>/app",
|
|
9
|
+
"<rootDir>/lib",
|
|
10
|
+
"<rootDir>/src",
|
|
11
|
+
],
|
|
12
|
+
testMatch: ["**/__tests__/**/*.test.ts", "**/__tests__/**/*.test.tsx"],
|
|
13
|
+
testPathIgnorePatterns: ["/node_modules/", "/.next/", "/dist/"],
|
|
14
|
+
// Ignore node_modules except fumadocs-* (ESM-only packages loaded via lib/source.ts → fumadocs-core/source).
|
|
15
|
+
// Mirrors the canonical jose carve-out used in apps/api, apps/mcp, and apps-paid/license-issuer.
|
|
16
|
+
// Added: issue #1077
|
|
17
|
+
transformIgnorePatterns: [
|
|
18
|
+
"/node_modules/(?!(\\.pnpm/)?fumadocs-[^/]*?@?[^/]*?(/|$))",
|
|
19
|
+
],
|
|
20
|
+
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
|
|
21
|
+
// Workspace packages publish ESM in dist/, but ts-jest runs in CommonJS.
|
|
22
|
+
// Map them to source so jest compiles them through the same transformer.
|
|
23
|
+
moduleNameMapper: {
|
|
24
|
+
// Mock server-only in Jest environments — the package throws by design
|
|
25
|
+
// outside Next.js. The real guard runs in production Next.js builds.
|
|
26
|
+
"^server-only$": "<rootDir>/../../__mocks__/server-only.ts",
|
|
27
|
+
// Fumadocs codegen output — produced by `pnpm --filter @working-theory/web build` into .source/
|
|
28
|
+
// The server entry uses top-level await + ESM-only fumadocs-mdx/runtime/server;
|
|
29
|
+
// map to a CJS stub so ts-jest can load modules that import lib/source.ts. (#1077)
|
|
30
|
+
// Stub lives in lib/__mocks__/ (committed) not .source/__mocks__/ (gitignored).
|
|
31
|
+
"^@/\\.source/server$": "<rootDir>/lib/__mocks__/source-server.js",
|
|
32
|
+
"^@/\\.source$": "<rootDir>/.source/index.ts",
|
|
33
|
+
"^@working-theory/page-renderer/testing$":
|
|
34
|
+
"<rootDir>/../../packages/page-renderer/src/testing.ts",
|
|
35
|
+
"^@working-theory/page-renderer$":
|
|
36
|
+
"<rootDir>/../../packages/page-renderer/src/index.tsx",
|
|
37
|
+
"^@working-theory/page-renderer/edge$":
|
|
38
|
+
"<rootDir>/../../packages/page-renderer/src/edge.ts",
|
|
39
|
+
"^@working-theory/analytics$": "<rootDir>/../../packages/analytics/src/index.ts",
|
|
40
|
+
"^@working-theory/api-client$": "<rootDir>/../../packages/api-client/src/index.ts",
|
|
41
|
+
"^@working-theory/content-adapters$":
|
|
42
|
+
"<rootDir>/../../packages/content-adapters/src/index.ts",
|
|
43
|
+
"^@working-theory/fumadocs-schema$":
|
|
44
|
+
"<rootDir>/../../packages/fumadocs-schema/src/index.ts",
|
|
45
|
+
"^@working-theory/license$": "<rootDir>/../../packages/license/src/index.ts",
|
|
46
|
+
"^@working-theory/metadata$": "<rootDir>/../../packages/metadata/src/index.ts",
|
|
47
|
+
// Dependency-free fragment subpaths (faq/person/review/…) → source, so CJS
|
|
48
|
+
// jest transforms them instead of choking on the dist ESM re-exports.
|
|
49
|
+
"^@working-theory/schema/(.*)$": "<rootDir>/../../packages/schema/src/$1.ts",
|
|
50
|
+
"^@working-theory/schema$": "<rootDir>/../../packages/schema/src/index.ts",
|
|
51
|
+
"^@working-theory/schema-pack-registry$":
|
|
52
|
+
"<rootDir>/../../packages/schema-pack-registry/src/index.ts",
|
|
53
|
+
"^@working-theory/sections-registry$":
|
|
54
|
+
"<rootDir>/../../packages/sections-registry/src/index.ts",
|
|
55
|
+
"^@working-theory/templates/shells$":
|
|
56
|
+
"<rootDir>/../../packages/templates/src/shells/index.ts",
|
|
57
|
+
"^@working-theory/templates$": "<rootDir>/../../packages/templates/src/index.ts",
|
|
58
|
+
"^@working-theory/ui$": "<rootDir>/../../packages/ui/src/index.ts",
|
|
59
|
+
"^@working-theory/ui/blocks$": "<rootDir>/../../packages/ui/src/blocks/index.ts",
|
|
60
|
+
"^@working-theory/ui/chrome$": "<rootDir>/../../packages/ui/src/chrome/index.ts",
|
|
61
|
+
"^@working-theory/ui/primitives$":
|
|
62
|
+
"<rootDir>/../../packages/ui/src/primitives/index.ts",
|
|
63
|
+
"^@working-theory/ui/panels$": "<rootDir>/../../packages/ui/src/panels/index.ts",
|
|
64
|
+
"^@working-theory/ui/sections$": "<rootDir>/../../packages/ui/src/sections/index.ts",
|
|
65
|
+
"^@working-theory/theme$": "<rootDir>/../../packages/theme/src/index.ts",
|
|
66
|
+
"^@working-theory/validation$": "<rootDir>/../../packages/validation/src/index.ts",
|
|
67
|
+
"^@working-theory/web-i18n$": "<rootDir>/../../packages/web-i18n/src/index.ts",
|
|
68
|
+
// next-mdx-remote/rsc is ESM-only; map to a CJS stub so ts-jest can load
|
|
69
|
+
// @working-theory/page-renderer source (which unconditionally imports MDXRemote).
|
|
70
|
+
// Per-test jest.mock() calls still override this mapper as expected.
|
|
71
|
+
"^next-mdx-remote/rsc$": "<rootDir>/lib/__mocks__/next-mdx-remote-rsc.js",
|
|
72
|
+
// CodeBlock's Shiki helper is ESM-only (cannot load in CJS jest); consumer
|
|
73
|
+
// tests transitively import CodeBlock but never highlight — stub to the
|
|
74
|
+
// plain-mono fallback. Must precede the generic `.js` mapper below.
|
|
75
|
+
"(^|/)code-highlight\\.js$":
|
|
76
|
+
"<rootDir>/../../packages/ui/src/blocks/code-highlight.jest-stub.ts",
|
|
77
|
+
"^(\\.{1,2}/.*)\\.js$": "$1",
|
|
78
|
+
},
|
|
79
|
+
setupFilesAfterEnv: ["<rootDir>/__tests__/setup.ts"],
|
|
80
|
+
transform: {
|
|
81
|
+
"^.+\\.(tsx?|jsx?|mjs)$": [
|
|
82
|
+
"ts-jest",
|
|
83
|
+
{
|
|
84
|
+
tsconfig: {
|
|
85
|
+
jsx: "react-jsx",
|
|
86
|
+
module: "commonjs",
|
|
87
|
+
target: "ES2020",
|
|
88
|
+
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
89
|
+
esModuleInterop: true,
|
|
90
|
+
skipLibCheck: true,
|
|
91
|
+
ignoreDeprecations: "6.0",
|
|
92
|
+
strict: true,
|
|
93
|
+
forceConsistentCasingInFileNames: true,
|
|
94
|
+
resolveJsonModule: true,
|
|
95
|
+
rootDir: ".",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CJS stub for next-mdx-remote/rsc — used by jest (CJS mode) to replace the
|
|
3
|
+
* ESM-only peer dependency that @working-theory/page-renderer imports at build time.
|
|
4
|
+
* Tests that need MDXRemote behaviour override this with jest.mock() locally.
|
|
5
|
+
*/
|
|
6
|
+
const React = require("react");
|
|
7
|
+
exports.MDXRemote = function MDXRemote({ source }) {
|
|
8
|
+
return React.createElement("div", {
|
|
9
|
+
"data-testid": "mdx-remote",
|
|
10
|
+
"data-source": source,
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest stub for @/.source/server — the fumadocs-mdx codegen output.
|
|
3
|
+
*
|
|
4
|
+
* The real .source/server.ts uses top-level await and ESM-only imports from
|
|
5
|
+
* fumadocs-mdx/runtime/server, which ts-jest cannot load in CJS mode.
|
|
6
|
+
* This stub provides the minimal shape needed by lib/source.ts so that
|
|
7
|
+
* the loader() call in that file does not throw at import time.
|
|
8
|
+
*
|
|
9
|
+
* Tests that exercise the blog/docs/llms routes inject their own source
|
|
10
|
+
* stubs via props, so the loader's output is never used in test execution.
|
|
11
|
+
*
|
|
12
|
+
* Referenced by: apps/web/jest.config.cjs moduleNameMapper '^@/\\.source/server$'
|
|
13
|
+
* Added: issue #1077 — fumadocs-core ESM + .source/server CJS compatibility
|
|
14
|
+
* Updated: issue #1459 — added docs collection stub alongside blog
|
|
15
|
+
*
|
|
16
|
+
* @note The real .source/ directory is gitignored (codegen output).
|
|
17
|
+
* This committed stub lives in lib/__mocks__/ so it is tracked by git.
|
|
18
|
+
*/
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
exports.blog = {
|
|
22
|
+
toFumadocsSource: function () {
|
|
23
|
+
return { files: [] };
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
exports.docs = {
|
|
28
|
+
toFumadocsSource: function () {
|
|
29
|
+
return { files: [] };
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for getOgImageUrl — the URL-builder helper.
|
|
3
|
+
*
|
|
4
|
+
* Contract:
|
|
5
|
+
* - Returns a URL-encoded path to /og with title + schemaType params
|
|
6
|
+
* - title and schemaType are properly URL-encoded
|
|
7
|
+
* - Missing schemaType produces no schemaType param
|
|
8
|
+
* - Special characters (ampersand, question mark, equals, spaces, unicode) are encoded
|
|
9
|
+
*/
|
|
10
|
+
import { getOgImageUrl } from "../og";
|
|
11
|
+
|
|
12
|
+
describe("getOgImageUrl", () => {
|
|
13
|
+
it("returns a URL with title param", () => {
|
|
14
|
+
const url = getOgImageUrl({ title: "Hello World", schemaType: "WebSite" });
|
|
15
|
+
expect(url).toContain("title=Hello+World");
|
|
16
|
+
expect(url).toContain("schemaType=WebSite");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("URL-encodes ampersand in title", () => {
|
|
20
|
+
const url = getOgImageUrl({ title: "A & B", schemaType: "WebSite" });
|
|
21
|
+
expect(url).not.toContain("title=A & B");
|
|
22
|
+
expect(url).toContain("A+%26+B");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("URL-encodes question mark in title", () => {
|
|
26
|
+
const url = getOgImageUrl({
|
|
27
|
+
title: "What is this?",
|
|
28
|
+
schemaType: "WebSite",
|
|
29
|
+
});
|
|
30
|
+
expect(url).not.toContain("?title=What is this?");
|
|
31
|
+
// The '?' in the title must be percent-encoded
|
|
32
|
+
expect(url).toMatch(/title=What[^&]*%3F/);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("URL-encodes equals sign in title", () => {
|
|
36
|
+
const url = getOgImageUrl({ title: "a=b", schemaType: "WebSite" });
|
|
37
|
+
expect(url).toContain("%3D");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("URL-encodes unicode characters", () => {
|
|
41
|
+
const url = getOgImageUrl({
|
|
42
|
+
title: "AI \u2014 Launch",
|
|
43
|
+
schemaType: "WebSite",
|
|
44
|
+
});
|
|
45
|
+
expect(url).not.toContain("AI \u2014 Launch");
|
|
46
|
+
expect(url).toContain("%E2%80%94");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("omits schemaType param when not provided", () => {
|
|
50
|
+
const url = getOgImageUrl({ title: "Hello" });
|
|
51
|
+
expect(url).not.toContain("schemaType");
|
|
52
|
+
expect(url).toContain("title=Hello");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("starts with /og? path", () => {
|
|
56
|
+
const url = getOgImageUrl({ title: "Test", schemaType: "Article" });
|
|
57
|
+
expect(url).toMatch(/^\/og\?/);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("encodes spaces as + or %20 consistently", () => {
|
|
61
|
+
const url = getOgImageUrl({ title: "Hello World" });
|
|
62
|
+
// URLSearchParams encodes spaces as +
|
|
63
|
+
expect(url).toContain("title=Hello+World");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth environment introspection helpers.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for:
|
|
5
|
+
* - AILK_AUTH_REQUIRED flag (whether protected routes redirect unauthenticated users)
|
|
6
|
+
* - Active provider list (which Better Auth providers are activated by env vars)
|
|
7
|
+
*
|
|
8
|
+
* No better-auth import — this module is safe to require in tests without the
|
|
9
|
+
* full Better Auth config being present.
|
|
10
|
+
*
|
|
11
|
+
* Better Auth env contract (apps/web):
|
|
12
|
+
* BETTER_AUTH_SECRET — required when any provider is active; signs session cookies.
|
|
13
|
+
* BETTER_AUTH_URL — base URL Better Auth uses for OAuth callback construction.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns true when AILK_AUTH_REQUIRED is set to "1" or "true".
|
|
18
|
+
* Default (unset or "0"/"false") = auth disabled; all routes public.
|
|
19
|
+
* This is the OSS-standalone default so scaffolded sites boot without any
|
|
20
|
+
* auth configuration.
|
|
21
|
+
*/
|
|
22
|
+
export function isAuthRequired(): boolean {
|
|
23
|
+
const val = process.env.AILK_AUTH_REQUIRED;
|
|
24
|
+
return val === "1" || val === "true";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns the list of provider IDs whose required env vars are all present.
|
|
29
|
+
* A provider is only included when every one of its required vars is non-empty.
|
|
30
|
+
*
|
|
31
|
+
* Provider IDs returned match the Better Auth socialProviders keys:
|
|
32
|
+
* "google" — Google OAuth (GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET)
|
|
33
|
+
* "github" — GitHub OAuth (GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET)
|
|
34
|
+
*
|
|
35
|
+
* "email" is reported as active when AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are
|
|
36
|
+
* set so existing consumers can detect intent, but Better Auth core does not
|
|
37
|
+
* ship a built-in magic-link provider — the wiring is deferred to a follow-up
|
|
38
|
+
* (see spec §7 "Out of Scope"). Treat "email" here as an env-presence signal,
|
|
39
|
+
* not a wired provider.
|
|
40
|
+
*/
|
|
41
|
+
export function getActiveProviderIds(): string[] {
|
|
42
|
+
const active: string[] = [];
|
|
43
|
+
|
|
44
|
+
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
|
|
45
|
+
active.push("google");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET) {
|
|
49
|
+
active.push("github");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (process.env.AUTH_EMAIL_SERVER && process.env.AUTH_EMAIL_FROM) {
|
|
53
|
+
active.push("email");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return active;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns true when at least one provider is configured.
|
|
61
|
+
* Used in middleware to skip Better Auth route setup entirely when no provider
|
|
62
|
+
* env vars are set.
|
|
63
|
+
*/
|
|
64
|
+
export function hasAnyProvider(): boolean {
|
|
65
|
+
return getActiveProviderIds().length > 0;
|
|
66
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter: Fumadocs blog source → `BlogListDataSchema` (issue #2713).
|
|
3
|
+
*
|
|
4
|
+
* The `@working-theory/ui` `BlogList` section is presentational (ADR-0027): it renders,
|
|
5
|
+
* the app maps source → data. This adapter turns `blogSource.getPages()` into
|
|
6
|
+
* the section's `data` prop, applying the field mapping from the issue:
|
|
7
|
+
*
|
|
8
|
+
* title ← frontmatter.title
|
|
9
|
+
* slug ← page.url (with the `/blog/` baseUrl prefix stripped, since
|
|
10
|
+
* the section re-prepends it: `href={`/blog/${slug}`}`)
|
|
11
|
+
* excerpt ← frontmatter.description
|
|
12
|
+
* publishedAt ← frontmatter.date
|
|
13
|
+
* coverImage ← frontmatter.image
|
|
14
|
+
* author ← frontmatter.author
|
|
15
|
+
* categories ← frontmatter.tags
|
|
16
|
+
*
|
|
17
|
+
* Locale-aware: the locale is threaded so callers can pass a locale-prefixed
|
|
18
|
+
* baseUrl for pagination when the route paginates (>1 page).
|
|
19
|
+
*/
|
|
20
|
+
import type { BlogListData } from "@working-theory/validation";
|
|
21
|
+
|
|
22
|
+
/** Frontmatter shape consumed here — must match `source.config.ts` blog schema. */
|
|
23
|
+
interface BlogFrontmatter {
|
|
24
|
+
title: string;
|
|
25
|
+
description: string;
|
|
26
|
+
date?: string;
|
|
27
|
+
updated?: string;
|
|
28
|
+
image?: string;
|
|
29
|
+
author?: { name: string; avatar?: string };
|
|
30
|
+
tags?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The subset of a Fumadocs page entry this adapter reads. */
|
|
34
|
+
interface BlogPageEntry {
|
|
35
|
+
url: string;
|
|
36
|
+
data: unknown;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Optional pagination inputs; pagination is emitted only when totalPages > 1. */
|
|
40
|
+
interface BlogListPagination {
|
|
41
|
+
page: number;
|
|
42
|
+
totalPages: number;
|
|
43
|
+
baseUrl: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type BlogPostPreview = BlogListData["posts"][number];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Strip the `/blog/` baseUrl prefix the section re-prepends when linking
|
|
50
|
+
* (`href={`/blog/${slug}`}`). The bare baseUrl (`/blog`, the index page that
|
|
51
|
+
* `getPages()` also returns) maps to an empty slug so the link stays `/blog/`
|
|
52
|
+
* rather than doubling the prefix.
|
|
53
|
+
*/
|
|
54
|
+
function toSlug(url: string): string {
|
|
55
|
+
if (url === "/blog") return "";
|
|
56
|
+
return url.replace(/^\/blog\//, "");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toPreview(entry: BlogPageEntry): BlogPostPreview {
|
|
60
|
+
const fm = entry.data as BlogFrontmatter;
|
|
61
|
+
return {
|
|
62
|
+
title: fm.title,
|
|
63
|
+
slug: toSlug(entry.url),
|
|
64
|
+
excerpt: fm.description,
|
|
65
|
+
publishedAt: fm.date ?? "",
|
|
66
|
+
...(fm.image ? { coverImage: { src: fm.image, alt: fm.title } } : {}),
|
|
67
|
+
...(fm.author
|
|
68
|
+
? {
|
|
69
|
+
author: {
|
|
70
|
+
name: fm.author.name,
|
|
71
|
+
...(fm.author.avatar
|
|
72
|
+
? { avatar: { src: fm.author.avatar, alt: fm.author.name } }
|
|
73
|
+
: {}),
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {}),
|
|
77
|
+
...(fm.tags && fm.tags.length > 0 ? { categories: fm.tags } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Map Fumadocs blog pages to `BlogList` section data.
|
|
83
|
+
*
|
|
84
|
+
* @param pages blog source entries (`blogSource.getPages()`).
|
|
85
|
+
* @param pagination optional pagination; emitted only when `totalPages > 1`.
|
|
86
|
+
*/
|
|
87
|
+
export function toBlogListData(
|
|
88
|
+
pages: BlogPageEntry[],
|
|
89
|
+
pagination?: BlogListPagination,
|
|
90
|
+
): BlogListData {
|
|
91
|
+
return {
|
|
92
|
+
posts: pages.map(toPreview),
|
|
93
|
+
...(pagination && pagination.totalPages > 1 ? { pagination } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter: Fumadocs blog post → `BlogPostDataSchema` (issue #2714).
|
|
3
|
+
*
|
|
4
|
+
* Maps a single post's frontmatter + generated table of contents to the
|
|
5
|
+
* `BlogPost` section's `data` prop. The compiled MDX body is NOT mapped here —
|
|
6
|
+
* it is a React node and is passed to the section via its `children` content
|
|
7
|
+
* slot (see the route). `data.body` is therefore left unset; the section
|
|
8
|
+
* renders `children` when present.
|
|
9
|
+
*
|
|
10
|
+
* title ← frontmatter.title
|
|
11
|
+
* publishedAt ← frontmatter.date
|
|
12
|
+
* updatedAt ← frontmatter.updated
|
|
13
|
+
* coverImage ← frontmatter.image
|
|
14
|
+
* author ← frontmatter.author
|
|
15
|
+
* categories ← frontmatter.tags
|
|
16
|
+
* toc ← page.data.toc (string-titled entries only)
|
|
17
|
+
*
|
|
18
|
+
* `readingTime` is omitted: it is not derivable from the compiled MDX body
|
|
19
|
+
* (a React component) without the raw text, so it is left unset per the
|
|
20
|
+
* "where available" contract.
|
|
21
|
+
*/
|
|
22
|
+
import type { BlogPostData } from "@working-theory/validation";
|
|
23
|
+
|
|
24
|
+
/** A Fumadocs TOC entry; `title` is a `ReactNode`, narrowed to strings here. */
|
|
25
|
+
interface TocEntry {
|
|
26
|
+
title: unknown;
|
|
27
|
+
url: string;
|
|
28
|
+
depth: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Frontmatter + generated fields this adapter reads from `page.data`. */
|
|
32
|
+
interface BlogPostPageData {
|
|
33
|
+
title: string;
|
|
34
|
+
description: string;
|
|
35
|
+
date?: string;
|
|
36
|
+
updated?: string;
|
|
37
|
+
image?: string;
|
|
38
|
+
author?: { name: string; avatar?: string };
|
|
39
|
+
tags?: string[];
|
|
40
|
+
toc?: TocEntry[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function toToc(entries: TocEntry[] | undefined): BlogPostData["toc"] {
|
|
44
|
+
if (!entries) return undefined;
|
|
45
|
+
const mapped = entries
|
|
46
|
+
.filter((e): e is TocEntry & { title: string } => typeof e.title === "string")
|
|
47
|
+
.map((e) => ({
|
|
48
|
+
id: e.url.replace(/^#/, ""),
|
|
49
|
+
text: e.title,
|
|
50
|
+
level: e.depth,
|
|
51
|
+
}));
|
|
52
|
+
return mapped.length > 0 ? mapped : undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Map a Fumadocs blog post's `page.data` to `BlogPost` section data.
|
|
57
|
+
* The MDX body renders via the section's `children` slot, not `data.body`.
|
|
58
|
+
*/
|
|
59
|
+
export function toBlogPostData(data: BlogPostPageData): BlogPostData {
|
|
60
|
+
const toc = toToc(data.toc);
|
|
61
|
+
return {
|
|
62
|
+
title: data.title,
|
|
63
|
+
publishedAt: data.date ?? "",
|
|
64
|
+
...(data.updated ? { updatedAt: data.updated } : {}),
|
|
65
|
+
...(data.image ? { coverImage: { src: data.image, alt: data.title } } : {}),
|
|
66
|
+
...(data.author
|
|
67
|
+
? {
|
|
68
|
+
author: {
|
|
69
|
+
name: data.author.name,
|
|
70
|
+
...(data.author.avatar
|
|
71
|
+
? { avatar: { src: data.author.avatar, alt: data.author.name } }
|
|
72
|
+
: {}),
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
: {}),
|
|
76
|
+
...(data.tags && data.tags.length > 0 ? { categories: data.tags } : {}),
|
|
77
|
+
...(toc ? { toc } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// nav-config.ts — Nav item registry for apps/web OSS template (#1451)
|
|
2
|
+
//
|
|
3
|
+
// The OSS template ships a focused navigation inventory — home, docs, and blog.
|
|
4
|
+
// Marketing-site items (pricing, services, about) belong in the per-site fork.
|
|
5
|
+
// Paths are locale-agnostic; Nav prefixes them with the active locale at render.
|
|
6
|
+
|
|
7
|
+
import type { NavItem } from "@working-theory/ui";
|
|
8
|
+
|
|
9
|
+
export const navItems: NavItem[] = [
|
|
10
|
+
{ labelKey: "home", path: "/" },
|
|
11
|
+
{ labelKey: "docs", path: "/docs" },
|
|
12
|
+
{ labelKey: "blog", path: "/blog" },
|
|
13
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Better Stack heartbeat util for apps/web (#1015).
|
|
2
|
+
//
|
|
3
|
+
// POSTs to BETTER_STACK_HEARTBEAT_URL when set, no-op when unset.
|
|
4
|
+
// Mirrors the `enabled: !!process.env.X` gating pattern from the Sentry
|
|
5
|
+
// configs (#884 / #886 / #894). POST failures are handled gracefully —
|
|
6
|
+
// the function returns without throwing so callers are never interrupted
|
|
7
|
+
// by a monitoring side-effect.
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Pings the Better Stack heartbeat endpoint.
|
|
11
|
+
*
|
|
12
|
+
* No-op when BETTER_STACK_HEARTBEAT_URL is not set (the OSS-install default).
|
|
13
|
+
* When set, POSTs to the URL. Network failures are caught and logged; they
|
|
14
|
+
* never propagate to the caller.
|
|
15
|
+
*/
|
|
16
|
+
export async function pingHeartbeat(): Promise<void> {
|
|
17
|
+
const url = process.env.BETTER_STACK_HEARTBEAT_URL;
|
|
18
|
+
if (!url) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
await fetch(url, { method: "POST" });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error("[better-stack] heartbeat ping failed:", err);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OG image URL builder.
|
|
3
|
+
*
|
|
4
|
+
* Returns a relative URL to the /og route with URL-encoded query params.
|
|
5
|
+
* Uses URLSearchParams so all special characters (& ? = spaces unicode) are
|
|
6
|
+
* correctly percent-encoded. Spaces encode as + per application/x-www-form-urlencoded.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
interface OgImageUrlOptions {
|
|
10
|
+
title: string;
|
|
11
|
+
schemaType?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getOgImageUrl({
|
|
15
|
+
title,
|
|
16
|
+
schemaType,
|
|
17
|
+
}: OgImageUrlOptions): string {
|
|
18
|
+
const params = new URLSearchParams({ title });
|
|
19
|
+
if (schemaType !== undefined) {
|
|
20
|
+
params.set("schemaType", schemaType);
|
|
21
|
+
}
|
|
22
|
+
return `/og?${params.toString()}`;
|
|
23
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrismaClient singleton for the Better Auth Prisma adapter in apps/web.
|
|
3
|
+
*
|
|
4
|
+
* Relocated from the deleted `@working-theory/auth-client` package as part of the
|
|
5
|
+
* Better Auth migration (#587). Driver adapter wrapping landed in Phase B
|
|
6
|
+
* of the Prisma 7 migration (#661) ahead of the v7 bump in Phase C.
|
|
7
|
+
*
|
|
8
|
+
* Only `apps/web/auth.ts` should import this — business-logic callers go
|
|
9
|
+
* through apps/api, never the database directly (architecture.yaml
|
|
10
|
+
* `apps/web` may_not_import_from `database`; the single-file singleton
|
|
11
|
+
* here is the documented exception, matching the pre-migration carve-out
|
|
12
|
+
* for NextAuth's adapter).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
import { PrismaClient } from "@working-theory/database";
|
|
17
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
18
|
+
|
|
19
|
+
declare global {
|
|
20
|
+
var __ailk_prisma: PrismaClient | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
|
|
24
|
+
|
|
25
|
+
export const prismaForAuth: PrismaClient =
|
|
26
|
+
globalThis.__ailk_prisma ??
|
|
27
|
+
new PrismaClient({
|
|
28
|
+
adapter,
|
|
29
|
+
log: process.env.NODE_ENV === "development" ? ["error", "warn"] : ["error"],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (process.env.NODE_ENV !== "production") {
|
|
33
|
+
globalThis.__ailk_prisma = prismaForAuth;
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fumadocs source loaders for the `/blog` and `/docs` routes.
|
|
3
|
+
*
|
|
4
|
+
* Two-file pattern (Fumadocs upstream convention):
|
|
5
|
+
* - `source.config.ts` — `defineDocs` config (frontmatter schema, dir)
|
|
6
|
+
* - `lib/source.ts` — `loader` instances consumed by route handlers
|
|
7
|
+
*
|
|
8
|
+
* `blog` and `docs` are generated at build time by `fumadocs-mdx/next`
|
|
9
|
+
* (`createMDX()` in `next.config.mjs`) into `apps/web/.source/server.ts`.
|
|
10
|
+
* Export names match the collections defined in `source.config.ts`.
|
|
11
|
+
* Each loader exposes `getPages()` and `getPage(slugs)` consumed by
|
|
12
|
+
* the respective catch-all route.
|
|
13
|
+
*
|
|
14
|
+
* fumadocs-mdx@15 replaced the standalone `createMDXSource(docs, meta)` helper
|
|
15
|
+
* with a `.toFumadocsSource()` method attached to the codegen-emitted
|
|
16
|
+
* collection. The runtime shape is otherwise unchanged.
|
|
17
|
+
*
|
|
18
|
+
* Per-app content directories (issue #1459, 2026-05-25): both collections now
|
|
19
|
+
* read from `apps/web/content/en/{blog,docs}/` rather than the shared
|
|
20
|
+
* `<repo-root>/content/en/blog/`.
|
|
21
|
+
*/
|
|
22
|
+
import { loader } from "fumadocs-core/source";
|
|
23
|
+
|
|
24
|
+
import { blog, docs } from "@/.source/server";
|
|
25
|
+
|
|
26
|
+
export const blogSource = loader({
|
|
27
|
+
baseUrl: "/blog",
|
|
28
|
+
source: blog.toFumadocsSource(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const docsSource = loader({
|
|
32
|
+
baseUrl: "/docs",
|
|
33
|
+
source: docs.toFumadocsSource(),
|
|
34
|
+
});
|