create-ailk 0.1.0 → 0.2.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 +124 -3
- package/component-catalog.md +456 -0
- package/dist/cli.js +92 -16
- package/dist/component-catalog.d.ts +11 -0
- package/dist/component-catalog.js +39 -0
- package/dist/copy.d.ts +7 -0
- package/dist/copy.js +24 -0
- package/dist/derive-architecture.d.ts +13 -0
- package/dist/derive-architecture.js +238 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +19 -2
- package/dist/lib/extract-module-bundle.d.ts +16 -0
- package/dist/lib/extract-module-bundle.js +184 -0
- package/dist/lib/fetch-module.d.ts +55 -0
- package/dist/lib/fetch-module.js +125 -0
- package/dist/lib/module-license-gate.d.ts +48 -0
- package/dist/lib/module-license-gate.js +67 -0
- package/dist/lib/module-tier.d.ts +35 -0
- package/dist/lib/module-tier.js +37 -0
- package/dist/module-architecture.d.ts +175 -0
- package/dist/module-architecture.js +663 -0
- package/dist/parse-args.d.ts +47 -1
- package/dist/parse-args.js +143 -2
- package/dist/programmatic.d.ts +160 -3
- package/dist/programmatic.js +196 -7
- package/dist/surfaces.d.ts +211 -0
- package/dist/surfaces.js +532 -0
- package/dist/sync-routes.d.ts +92 -0
- package/dist/sync-routes.js +350 -0
- package/package.json +12 -5
- package/templates/.claude/rules/architecture.md +6 -2
- package/templates/.claude/skills/README.md +9 -9
- package/templates/.claude/skills/add-schema/SKILL.md +14 -7
- package/templates/.claude/skills/add-schema/references/schema-types.md +109 -6
- package/templates/.claude/skills/provision-config/SKILL.md +1 -1
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +498 -1
- package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +370 -0
- package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +376 -0
- package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +471 -0
- package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +365 -0
- package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +60 -0
- package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +446 -0
- package/templates/.claude/skills/suggest-site-pages/references/categories.md +4 -4
- package/templates/.env.example +126 -2
- package/templates/CLAUDE.md +11 -5
- package/templates/README.md +1 -1
- package/templates/apps/api/.env.example +38 -0
- package/templates/apps/api/CLAUDE.md +78 -1
- package/templates/apps/api/LICENSE +201 -0
- package/templates/apps/api/api/index.ts +6 -141
- package/templates/apps/api/jest.config.cjs +16 -0
- package/templates/apps/api/package.json +22 -6
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +141 -0
- package/templates/apps/api/src/__tests__/server.test.ts +46 -0
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +211 -0
- package/templates/apps/api/src/bin/abandon-sweep.ts +42 -0
- package/templates/apps/api/src/bin/deliverable-resend.ts +144 -0
- package/templates/apps/api/src/bin/deliverable-upload.ts +114 -0
- package/templates/apps/api/src/bin/followup-sweep.ts +44 -0
- package/templates/apps/api/src/bin/listing-csv-sweep.ts +46 -0
- package/templates/apps/api/src/bin/seed-presets.ts +58 -0
- package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +104 -0
- package/templates/apps/api/src/bin/session-retention-sweep.ts +46 -0
- package/templates/apps/api/src/cli.ts +5 -11
- package/templates/apps/api/src/config/index.ts +35 -0
- package/templates/apps/api/src/config/modules.ts +43 -0
- package/templates/apps/api/src/lib/__mocks__/prisma-client.js +11 -0
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +241 -0
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +2 -2
- package/templates/apps/api/src/lib/site.ts +16 -0
- package/templates/apps/api/src/lib/stripe.ts +22 -0
- package/templates/apps/api/src/lib/tenant-db.ts +225 -0
- package/templates/apps/api/src/lib/ws-token.ts +91 -0
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +7 -1
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +7 -1
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +91 -4
- package/templates/apps/api/src/middleware/auth.ts +43 -8
- package/templates/apps/api/src/middleware/rate-limit.ts +78 -3
- package/templates/apps/api/src/middleware/tenant.ts +99 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +92 -0
- package/templates/apps/api/src/openapi/spec.ts +312 -3
- package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +175 -0
- package/templates/apps/api/src/routes/aeo/index.ts +107 -0
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +5 -2
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +22 -3
- package/templates/apps/api/src/routes/auth/tokens.ts +13 -1
- package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +450 -0
- package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +262 -0
- package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +436 -0
- package/templates/apps/api/src/routes/billing/index.ts +36 -0
- package/templates/apps/api/src/routes/billing/portal.ts +182 -0
- package/templates/apps/api/src/routes/billing/read.ts +75 -0
- package/templates/apps/api/src/routes/billing/usage.ts +153 -0
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +99 -0
- package/templates/apps/api/src/routes/checkout/sessions.ts +20 -8
- package/templates/apps/api/src/routes/content/create.ts +1 -0
- package/templates/apps/api/src/routes/content/delete.ts +1 -0
- package/templates/apps/api/src/routes/content/index.ts +42 -6
- package/templates/apps/api/src/routes/content/update.ts +1 -0
- package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +393 -0
- package/templates/apps/api/src/routes/deliverables/index.ts +200 -0
- package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +443 -0
- package/templates/apps/api/src/routes/flow-checkouts/index.ts +82 -0
- package/templates/apps/api/src/routes/flows/README.md +147 -0
- package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +752 -0
- package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +671 -0
- package/templates/apps/api/src/routes/flows/index.ts +202 -0
- package/templates/apps/api/src/routes/flows/recommender.ts +443 -0
- package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +438 -31
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +10 -10
- package/templates/apps/api/src/routes/leads/index.ts +43 -9
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +558 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +815 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +869 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +221 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +468 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +424 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +707 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +375 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +467 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +566 -0
- package/templates/apps/api/src/routes/project-listings/get.ts +70 -0
- package/templates/apps/api/src/routes/project-listings/index.ts +120 -0
- package/templates/apps/api/src/routes/project-listings/list.ts +47 -0
- package/templates/apps/api/src/routes/project-listings/me.ts +76 -0
- package/templates/apps/api/src/routes/project-listings/patch-copy.ts +222 -0
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +97 -0
- package/templates/apps/api/src/routes/project-listings/patch.ts +136 -0
- package/templates/apps/api/src/routes/project-listings/public.ts +52 -0
- package/templates/apps/api/src/routes/project-listings/respond.ts +37 -0
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +22 -0
- package/templates/apps/api/src/routes/project-listings/start.ts +106 -0
- package/templates/apps/api/src/routes/project-listings/submit.ts +122 -0
- package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +490 -0
- package/templates/apps/api/src/routes/schedule/index.ts +249 -0
- package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +385 -0
- package/templates/apps/api/src/routes/slack/actions.ts +177 -0
- package/templates/apps/api/src/routes/slack/index.ts +38 -0
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +16 -6
- package/templates/apps/api/src/routes/test/auth/session.ts +8 -6
- package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +577 -0
- package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +78 -0
- package/templates/apps/api/src/routes/waitlist-experiments/index.ts +41 -0
- package/templates/apps/api/src/routes/waitlist-experiments/list.ts +64 -0
- package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +42 -0
- package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +84 -0
- package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +119 -0
- package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +238 -0
- package/templates/apps/api/src/routes/waitlist-signups/index.ts +101 -0
- package/templates/apps/api/src/routes/webhooks/README.md +35 -12
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +315 -0
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +270 -0
- package/templates/apps/api/src/routes/webhooks/stripe.ts +248 -20
- package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +356 -0
- package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +671 -0
- package/templates/apps/api/src/routes/workspaces/config.ts +125 -0
- package/templates/apps/api/src/routes/workspaces/index.ts +194 -0
- package/templates/apps/api/src/routes/workspaces/sessions.ts +218 -0
- package/templates/apps/api/src/server.ts +307 -7
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +489 -0
- package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +475 -0
- package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +132 -0
- package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +65 -0
- package/templates/apps/api/src/services/__tests__/consent.test.ts +282 -0
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +523 -0
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +359 -0
- package/templates/apps/api/src/services/__tests__/entitlements.test.ts +142 -0
- package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +425 -0
- package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +2840 -0
- package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +393 -0
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +8 -8
- package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +560 -0
- package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +684 -0
- package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +406 -0
- package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +290 -0
- package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +736 -0
- package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +475 -0
- package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +340 -0
- package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +983 -0
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +278 -0
- package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +71 -0
- package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +379 -0
- package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +941 -0
- package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +588 -0
- package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +768 -0
- package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +1314 -0
- package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +341 -0
- package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +567 -0
- package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +474 -0
- package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +354 -0
- package/templates/apps/api/src/services/abandon-email.ts +307 -0
- package/templates/apps/api/src/services/aeo-score.ts +288 -0
- package/templates/apps/api/src/services/answer-distributions.ts +138 -0
- package/templates/apps/api/src/services/consent.ts +236 -0
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +523 -0
- package/templates/apps/api/src/services/entitlements.ts +102 -0
- package/templates/apps/api/src/services/flow-aggregate.ts +232 -0
- package/templates/apps/api/src/services/flow-checkouts.ts +123 -0
- package/templates/apps/api/src/services/flow-engine.ts +1296 -0
- package/templates/apps/api/src/services/lead-promotion.ts +176 -0
- package/templates/apps/api/src/services/lead-routing.ts +3 -3
- package/templates/apps/api/src/services/listing-config.ts +102 -0
- package/templates/apps/api/src/services/listing-csv-sweep.ts +455 -0
- package/templates/apps/api/src/services/listing-promotion.ts +342 -0
- package/templates/apps/api/src/services/playbook-compile.ts +398 -0
- package/templates/apps/api/src/services/playbook-render.ts +263 -0
- package/templates/apps/api/src/services/project-listing-decision.ts +510 -0
- package/templates/apps/api/src/services/project-listing-flow.ts +426 -0
- package/templates/apps/api/src/services/project-listing-issue.ts +251 -0
- package/templates/apps/api/src/services/project-listings.ts +1472 -0
- package/templates/apps/api/src/services/recommender-capture.ts +835 -0
- package/templates/apps/api/src/services/scheduling/cal-provider.ts +392 -0
- package/templates/apps/api/src/services/scheduling/index.ts +63 -0
- package/templates/apps/api/src/services/scheduling/types.ts +88 -0
- package/templates/apps/api/src/services/slack-notify.ts +240 -0
- package/templates/apps/api/src/services/tenant-context.ts +451 -0
- package/templates/apps/api/src/services/usage-aggregation.ts +516 -0
- package/templates/apps/api/src/services/usage-credits.ts +340 -0
- package/templates/apps/api/src/services/usage-metering.ts +699 -0
- package/templates/apps/api/src/services/waitlist-dashboard.ts +947 -0
- package/templates/apps/api/src/services/waitlist-experiments.ts +213 -0
- package/templates/apps/api/src/services/waitlist-followup.ts +486 -0
- package/templates/apps/api/src/services/waitlist-scoring.ts +166 -0
- package/templates/apps/api/src/services/waitlist-signups.ts +165 -0
- package/templates/apps/api/src/vercel-handler.ts +165 -0
- package/templates/apps/api/tsconfig.json +0 -12
- package/templates/apps/mcp/CLAUDE.md +19 -9
- package/templates/apps/mcp/LICENSE +201 -0
- package/templates/apps/mcp/__tests__/create_page.test.ts +1 -0
- package/templates/apps/mcp/__tests__/delete_page.test.ts +1 -0
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +105 -0
- package/templates/apps/mcp/__tests__/parity.test.ts +70 -6
- package/templates/apps/mcp/__tests__/request_callback.test.ts +4 -4
- package/templates/apps/mcp/__tests__/schedule_tools.test.ts +242 -0
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +4 -4
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +4 -4
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +47 -0
- package/templates/apps/mcp/__tests__/update_page.test.ts +1 -0
- package/templates/apps/mcp/package.json +6 -4
- package/templates/apps/mcp/src/config/modules.ts +37 -0
- package/templates/apps/mcp/src/server.ts +109 -18
- package/templates/apps/mcp/src/tools/capture_lead.ts +1 -1
- package/templates/apps/mcp/src/tools/create_booking.ts +58 -0
- package/templates/apps/mcp/src/tools/create_page.ts +1 -0
- package/templates/apps/mcp/src/tools/delete_page.ts +1 -0
- package/templates/apps/mcp/src/tools/get_event_meta.ts +55 -0
- package/templates/apps/mcp/src/tools/get_flow.ts +61 -0
- package/templates/apps/mcp/src/tools/index.ts +25 -0
- package/templates/apps/mcp/src/tools/list_availability.ts +67 -0
- package/templates/apps/mcp/src/tools/purchase.ts +3 -0
- package/templates/apps/mcp/src/tools/submit_flow_step.ts +83 -0
- package/templates/apps/mcp/src/tools/update_page.ts +1 -0
- package/templates/apps/mcp/tsconfig.json +1 -9
- package/templates/apps/web/.env.example +44 -0
- package/templates/apps/web/CLAUDE.md +28 -0
- package/templates/apps/web/LICENSE +201 -0
- package/templates/apps/web/__tests__/__mocks__/code-highlight.jest-stub.ts +24 -0
- package/templates/apps/web/__tests__/__mocks__/next-intl-server.ts +33 -0
- package/templates/apps/web/__tests__/__mocks__/next-intl.ts +18 -0
- package/templates/apps/web/__tests__/__mocks__/server-only.ts +13 -0
- package/templates/apps/web/__tests__/__mocks__/style-mock.js +4 -0
- package/templates/apps/web/__tests__/__mocks__/vercel-analytics-server.ts +9 -0
- package/templates/apps/web/__tests__/jest-support/import-meta-transformer.cjs +90 -0
- package/templates/apps/web/__tests__/setup.ts +22 -32
- package/templates/apps/web/app/.well-known/ai-plugin.json/route.ts +6 -3
- package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +8 -2
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +260 -0
- package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +263 -0
- package/templates/apps/web/app/[locale]/(authed)/account/sign-out-button.tsx +39 -0
- package/templates/apps/web/app/[locale]/(authed)/layout.tsx +54 -0
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +96 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +309 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +149 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +273 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/gate.test.tsx +172 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +171 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +179 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +116 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ForbiddenState.tsx +24 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +66 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +61 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +114 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +139 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +85 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +67 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/format.ts +111 -0
- package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +179 -0
- package/templates/apps/web/app/[locale]/about/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +6 -1
- package/templates/apps/web/app/[locale]/careers/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/careers/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/case-studies/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/case-studies/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/clients/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/clients/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/contact/ContactForm.tsx +21 -1
- package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +188 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/ConversationalIntakeWrapper.test.tsx +242 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +29 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/intake-analytics.test.ts +51 -0
- package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +39 -15
- package/templates/apps/web/app/[locale]/contact/contact.actions.ts +21 -3
- package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +49 -0
- package/templates/apps/web/app/[locale]/contact/intake-script.ts +66 -0
- package/templates/apps/web/app/[locale]/contact/page.tsx +14 -4
- package/templates/apps/web/app/[locale]/courses/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/courses/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +1 -0
- package/templates/apps/web/app/[locale]/downloads/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/downloads/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/events/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/events/__tests__/page-renderer-migration.test.tsx +12 -2
- package/templates/apps/web/app/[locale]/events/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/faq/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +265 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +445 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +341 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +287 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +302 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +128 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +254 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +144 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +108 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +532 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +121 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +457 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +396 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +114 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +52 -0
- package/templates/apps/web/app/[locale]/how-to/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/integrations/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/integrations/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/launch-service/page.tsx +14 -1
- package/templates/apps/web/app/[locale]/layout.tsx +127 -16
- package/templates/apps/web/app/[locale]/page.tsx +10 -1
- package/templates/apps/web/app/[locale]/partners/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/partners/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/products/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/products/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/projects/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/projects/__tests__/page-renderer-migration.test.tsx +10 -0
- package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +110 -0
- package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +96 -0
- package/templates/apps/web/app/[locale]/projects/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/resources/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/resources/__tests__/page-renderer-migration.test.tsx +12 -2
- package/templates/apps/web/app/[locale]/resources/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +117 -0
- package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +96 -0
- package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +92 -0
- package/templates/apps/web/app/[locale]/schedule/page.tsx +82 -0
- package/templates/apps/web/app/[locale]/services/[slug]/page.tsx +9 -0
- package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +3 -3
- package/templates/apps/web/app/[locale]/services/page.tsx +9 -1
- package/templates/apps/web/app/[locale]/sign-in/__tests__/next-path.test.ts +31 -0
- package/templates/apps/web/app/[locale]/sign-in/__tests__/page.test.tsx +152 -0
- package/templates/apps/web/app/[locale]/sign-in/next-path.ts +0 -0
- package/templates/apps/web/app/[locale]/sign-in/page.tsx +83 -0
- package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +123 -0
- package/templates/apps/web/app/[locale]/software/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/tech-articles/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/[locale]/testimonials/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/testimonials/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/thanks/[slug]/__tests__/page.test.tsx +93 -0
- package/templates/apps/web/app/[locale]/thanks/[slug]/page.tsx +48 -0
- package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +11 -1
- package/templates/apps/web/app/[locale]/use-cases/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/whitepapers/[slug]/page.tsx +13 -1
- package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
- package/templates/apps/web/app/globals.css +35 -0
- package/templates/apps/web/app/llms.txt/route.ts +2 -1
- package/templates/apps/web/app/og/route.tsx +10 -2
- package/templates/apps/web/auth.ts +8 -0
- package/templates/apps/web/components/sign-out-trigger.tsx +42 -0
- package/templates/apps/web/content/en/blog/README.txt +25 -0
- package/templates/apps/web/content/en/docs/index.mdx +28 -0
- package/templates/apps/web/jest.config.cjs +90 -27
- package/templates/apps/web/lib/__tests__/site-brand.test.ts +119 -0
- package/templates/apps/web/lib/__tests__/site-theme.test.ts +112 -0
- package/templates/apps/web/lib/__tests__/structured-data.test.tsx +499 -0
- package/templates/apps/web/lib/account-config.ts +13 -0
- package/templates/apps/web/lib/server-api.ts +85 -0
- package/templates/apps/web/lib/site-brand.tsx +121 -0
- package/templates/apps/web/lib/site-theme.ts +74 -0
- package/templates/apps/web/messages/en.json +275 -7
- package/templates/apps/web/middleware.ts +11 -3
- package/templates/apps/web/next.config.mjs +8 -2
- package/templates/apps/web/package.json +17 -7
- package/templates/apps/web/postcss.config.mjs +23 -0
- package/templates/apps/web/public/.well-known/security.txt +3 -3
- package/templates/apps/web/src/lib/routes.ts +15 -2
- package/templates/apps/web/tsconfig.json +1 -16
- package/templates/content/_site.mdx +36 -25
- package/templates/content/en/AboutPage/about.mdx +24 -14
- package/templates/content/en/ContactPage/contact.mdx +23 -14
- package/templates/content/en/FAQPage/faq.mdx +10 -392
- package/templates/content/en/HomePage/home.mdx +14 -285
- package/templates/database/CHANGELOG.md +443 -0
- package/templates/database/LICENSE +201 -0
- package/templates/database/README.md +3 -1
- package/templates/database/__tests__/flows-listing-diagnostic.test.ts +392 -0
- package/templates/database/__tests__/flows-presets.test.ts +173 -0
- package/templates/database/__tests__/prefixed-ids.db.test.ts +146 -0
- package/templates/database/__tests__/seed.test.ts +88 -0
- package/templates/database/__tests__/user-cascade.test.ts +19 -4
- package/templates/database/auth/schema.prisma +521 -0
- package/templates/database/config/schema.prisma +234 -0
- package/templates/database/content/schema.prisma +263 -0
- package/templates/database/flows/listing-diagnostic.ts +182 -0
- package/templates/database/flows/presets.ts +315 -0
- package/templates/database/inbox/__tests__/schema.test.ts +4 -0
- package/templates/database/inbox/schema.prisma +574 -3
- package/templates/database/jest.config.cjs +8 -0
- package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +201 -0
- package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +67 -0
- package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +46 -0
- package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +25 -0
- package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +49 -0
- package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +197 -0
- package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +32 -0
- package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +22 -0
- package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +151 -0
- package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +223 -0
- package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +22 -0
- package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +32 -0
- package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +40 -0
- package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +4 -0
- package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +2 -0
- package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +2 -0
- package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +29 -0
- package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +6 -0
- package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +39 -0
- package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +24 -0
- package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +3 -0
- package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +33 -0
- package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +30 -0
- package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +47 -0
- package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +16 -0
- package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +47 -0
- package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +10 -0
- package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +26 -0
- package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +90 -0
- package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +174 -0
- package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +14 -0
- package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +25 -0
- package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +32 -0
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +71 -0
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +30 -0
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +49 -0
- package/templates/database/ops/schema.prisma +27 -0
- package/templates/database/package.json +42 -4
- package/templates/database/prisma.config.ts +1 -1
- package/templates/database/schema.prisma +19 -435
- package/templates/database/seed-test.ts +14 -4
- package/templates/database/seed.ts +148 -0
- package/templates/database/tenancy.ts +45 -0
- package/templates/database/tsconfig.flows.json +15 -0
- package/templates/database/tsconfig.json +7 -1
- package/templates/database/tsconfig.tenancy.json +14 -0
- package/templates/package.json +30 -55
- package/templates/pnpm-workspace.yaml +0 -3
- package/templates/project.yaml +1 -1
- package/templates/tsconfig.json +1 -37
- package/templates/apps/web/__tests__/auth/adversarial/cookie-attributes.test.ts +0 -94
- package/templates/apps/web/__tests__/auth/adversarial/oauth-state-parameter.test.ts +0 -75
- package/templates/apps/web/__tests__/auth/adversarial/redirect-uri-allowlist.test.ts +0 -82
- package/templates/apps/web/__tests__/auth/env-helpers.test.ts +0 -168
- package/templates/apps/web/__tests__/authority-list-routes.test.tsx +0 -208
- package/templates/apps/web/__tests__/better-stack.test.ts +0 -66
- package/templates/apps/web/__tests__/blog-dir-resolution.test.ts +0 -87
- package/templates/apps/web/__tests__/blog-source-populated.test.ts +0 -130
- package/templates/apps/web/__tests__/data-testid-coverage.test.tsx +0 -60
- package/templates/apps/web/__tests__/google-analytics.test.tsx +0 -104
- package/templates/apps/web/__tests__/i18n/middleware.test.ts +0 -119
- package/templates/apps/web/__tests__/i18n/routing.test.ts +0 -114
- package/templates/apps/web/__tests__/i18n/translations.test.ts +0 -191
- package/templates/apps/web/__tests__/json-ld.test.ts +0 -98
- package/templates/apps/web/__tests__/knowledge-events-routes.test.tsx +0 -580
- package/templates/apps/web/__tests__/layout-stealth.test.ts +0 -39
- package/templates/apps/web/__tests__/lighthouse-fixtures/improvement-image-shrink.tsx +0 -103
- package/templates/apps/web/__tests__/lighthouse-fixtures/override-fixture.md +0 -114
- package/templates/apps/web/__tests__/lighthouse-fixtures/regression-bloat.tsx +0 -94
- package/templates/apps/web/__tests__/page.test.tsx +0 -230
- package/templates/apps/web/__tests__/products-services-phase1.test.tsx +0 -321
- package/templates/apps/web/__tests__/projects-routes.test.tsx +0 -392
- package/templates/apps/web/__tests__/resources-downloads-integrations-phase2.test.tsx +0 -475
- package/templates/apps/web/__tests__/routes/ai-plugin-json.test.ts +0 -53
- package/templates/apps/web/__tests__/routes/blog-route.test.tsx +0 -191
- package/templates/apps/web/__tests__/routes/llms-txt.test.ts +0 -123
- package/templates/apps/web/__tests__/routes/robots-txt.test.ts +0 -52
- package/templates/apps/web/__tests__/routes/sitemap-xml.test.ts +0 -78
- package/templates/apps/web/__tests__/routes/well-known-mcp.test.ts +0 -203
- package/templates/apps/web/__tests__/section-routes.test.tsx +0 -693
- package/templates/apps/web/__tests__/security-headers.test.ts +0 -201
- package/templates/apps/web/__tests__/sentry-config.test.ts +0 -116
- package/templates/apps/web/__tests__/sitemap-locales.test.ts +0 -415
- package/templates/apps/web/__tests__/standalone-informational-routes.test.tsx +0 -844
- package/templates/apps/web/app/[locale]/__tests__/layout.test.tsx +0 -120
- package/templates/apps/web/app/[locale]/__tests__/page-renderer-migration.test.tsx +0 -202
- package/templates/apps/web/app/__tests__/error-boundaries.test.tsx +0 -152
- package/templates/apps/web/content/en/blog/index.mdx +0 -15
- package/templates/apps/web/content/en/blog/launching-ailk.mdx +0 -20
- package/templates/apps/web/content/en/docs/getting-started.mdx +0 -30
- package/templates/content/.gitkeep +0 -0
- package/templates/content/CLAUDE.md +0 -85
- package/templates/content/ar/HomePage/home.mdx +0 -123
- package/templates/content/ar/_site.mdx +0 -35
- package/templates/content/de/_site.mdx +0 -29
- package/templates/content/en/.gitkeep +0 -0
- package/templates/content/en/AboutPage/about.schema.json +0 -82
- package/templates/content/en/BookCall/book-call.mdx +0 -19
- package/templates/content/en/BookCall/book-call.schema.json +0 -121
- package/templates/content/en/BreadcrumbList/site-breadcrumbs.mdx +0 -20
- package/templates/content/en/CareersList/careers.mdx +0 -24
- package/templates/content/en/CaseStudiesList/case-studies.mdx +0 -22
- package/templates/content/en/CaseStudiesList/showcase.mdx +0 -8
- package/templates/content/en/CaseStudy/ailk-aeo-rollout.mdx +0 -32
- package/templates/content/en/CaseStudy/schema-builder-migration.mdx +0 -41
- package/templates/content/en/ClientsList/clients.mdx +0 -38
- package/templates/content/en/ContactPage/contact.schema.json +0 -100
- package/templates/content/en/ContactPoint/primary.mdx +0 -14
- package/templates/content/en/Course/aeo-fundamentals.mdx +0 -37
- package/templates/content/en/Course/schema-builder-workshop.mdx +0 -62
- package/templates/content/en/CoursesList/courses.mdx +0 -22
- package/templates/content/en/DownloadsList/downloads.mdx +0 -22
- package/templates/content/en/Event/aeo-office-hours-may-2026.mdx +0 -39
- package/templates/content/en/Event/ailk-launch-day-2026.mdx +0 -35
- package/templates/content/en/EventsList/events.mdx +0 -26
- package/templates/content/en/FAQPage/faq.schema.json +0 -231
- package/templates/content/en/GlossaryList/glossary.mdx +0 -19
- package/templates/content/en/GlossaryList/glossary.schema.json +0 -300
- package/templates/content/en/HomePage/home.schema.json +0 -88
- package/templates/content/en/HomePage/launch-service.mdx +0 -475
- package/templates/content/en/HomePage/launch-service.schema.json +0 -138
- package/templates/content/en/HowTo/add-mdx-content.mdx +0 -38
- package/templates/content/en/HowTo/configure-aeo-scoring.mdx +0 -35
- package/templates/content/en/HowTo/set-up-json-ld.mdx +0 -36
- package/templates/content/en/Integration/github-actions.mdx +0 -31
- package/templates/content/en/Integration/openai-api.mdx +0 -26
- package/templates/content/en/Integration/vercel.mdx +0 -32
- package/templates/content/en/IntegrationsList/integrations.mdx +0 -22
- package/templates/content/en/JobPosting/content-strategist.mdx +0 -46
- package/templates/content/en/JobPosting/developer-advocate.mdx +0 -47
- package/templates/content/en/JobPosting/senior-fullstack-engineer.mdx +0 -57
- package/templates/content/en/LandingPage/aeo-audit.mdx +0 -19
- package/templates/content/en/LandingPage/aeo-audit.schema.json +0 -92
- package/templates/content/en/LandingPage/agency-waitlist.mdx +0 -340
- package/templates/content/en/LandingPage/agency-waitlist.schema.json +0 -152
- package/templates/content/en/LandingPage/developers.mdx +0 -19
- package/templates/content/en/LandingPage/developers.schema.json +0 -109
- package/templates/content/en/LandingPage/for-agencies.mdx +0 -390
- package/templates/content/en/LandingPage/for-agencies.schema.json +0 -107
- package/templates/content/en/LandingPage/for-ai-search-agencies.mdx +0 -417
- package/templates/content/en/LandingPage/for-ai-search-agencies.schema.json +0 -105
- package/templates/content/en/LandingPage/for-businesses.mdx +0 -19
- package/templates/content/en/LandingPage/for-businesses.schema.json +0 -96
- package/templates/content/en/LandingPage/platform.mdx +0 -369
- package/templates/content/en/LandingPage/platform.schema.json +0 -166
- package/templates/content/en/LandingPage/vs-ai-website-builders.mdx +0 -19
- package/templates/content/en/LandingPage/vs-ai-website-builders.schema.json +0 -102
- package/templates/content/en/LandingPage/vs-wordpress.mdx +0 -19
- package/templates/content/en/LandingPage/vs-wordpress.schema.json +0 -53
- package/templates/content/en/NewsletterSignup/newsletter.mdx +0 -236
- package/templates/content/en/NewsletterSignup/newsletter.schema.json +0 -91
- package/templates/content/en/Organization/site-owner.mdx +0 -16
- package/templates/content/en/Partner/prisma.mdx +0 -31
- package/templates/content/en/Partner/supabase.mdx +0 -30
- package/templates/content/en/Partner/vercel.mdx +0 -28
- package/templates/content/en/PartnersList/partners.mdx +0 -22
- package/templates/content/en/Person/founder.mdx +0 -18
- package/templates/content/en/Pricing/pricing.mdx +0 -538
- package/templates/content/en/Pricing/pricing.schema.json +0 -209
- package/templates/content/en/PrivacyPage/privacy.mdx +0 -165
- package/templates/content/en/PrivacyPage/privacy.schema.json +0 -64
- package/templates/content/en/Product/ailk.mdx +0 -19
- package/templates/content/en/Product/ailk.schema.json +0 -94
- package/templates/content/en/Product/api-launch-kit.mdx +0 -26
- package/templates/content/en/Product/launch-kit.mdx +0 -28
- package/templates/content/en/ProductsList/products.mdx +0 -26
- package/templates/content/en/Project/ailk-phase-2.mdx +0 -54
- package/templates/content/en/ProjectsList/projects.mdx +0 -25
- package/templates/content/en/ResourceDetail/aeo-scoring-guide.mdx +0 -27
- package/templates/content/en/ResourceDetail/content-model-whitepaper.mdx +0 -28
- package/templates/content/en/ResourceDetail/schema-org-quick-reference.mdx +0 -39
- package/templates/content/en/ResourcesHub/resources.mdx +0 -22
- package/templates/content/en/Service/consulting.mdx +0 -22
- package/templates/content/en/Service/implementation.mdx +0 -30
- package/templates/content/en/Service/launch-service.mdx +0 -232
- package/templates/content/en/Service/launch.mdx +0 -228
- package/templates/content/en/ServicesList/services.mdx +0 -84
- package/templates/content/en/SoftwareProduct/ailk-aeo.mdx +0 -44
- package/templates/content/en/SoftwareProduct/ailk-content-adapters.mdx +0 -47
- package/templates/content/en/SoftwareProduct/ailk-schema.mdx +0 -49
- package/templates/content/en/TeamList/team.mdx +0 -63
- package/templates/content/en/TeamMember/founder.mdx +0 -72
- package/templates/content/en/TermsPage/terms.mdx +0 -19
- package/templates/content/en/TermsPage/terms.schema.json +0 -99
- package/templates/content/en/TestimonialsList/testimonials.mdx +0 -44
- package/templates/content/en/UseCasesList/use-cases.mdx +0 -30
- package/templates/content/en/Whitepaper/ax-first-product-development.mdx +0 -27
- package/templates/content/en/Whitepaper/open-core-commercial-strategy.mdx +0 -27
- package/templates/content/en/Whitepaper/structured-data-for-answer-engines.mdx +0 -31
- package/templates/content/en-XA/AboutPage/about.mdx +0 -8
- package/templates/content/en-XA/FAQPage/faq.mdx +0 -8
- package/templates/content/en-XA/HomePage/home.mdx +0 -8
- package/templates/content/es/_site.mdx +0 -30
- package/templates/content/fr/_site.mdx +0 -30
- package/templates/content/ja/_site.mdx +0 -30
- package/templates/content/pt-BR/AboutPage/about.mdx +0 -8
- package/templates/content/pt-BR/FAQPage/faq.mdx +0 -8
- package/templates/content/pt-BR/HomePage/home.mdx +0 -23
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; mirrors abandon-sweep.ts's coverage-ignore
|
|
3
|
+
rationale — real entry-point semantics run the compiled dist directly, and
|
|
4
|
+
the DB write it performs (prisma.deliverableAsset.upsert) is exercised
|
|
5
|
+
through the same mocked-prisma double the service-layer tests already use
|
|
6
|
+
(apps/api/src/lib/__mocks__/prisma.ts § deliverableAsset). This file is a
|
|
7
|
+
thin entry: parse args, read the file, refuse the size cap, upsert. */
|
|
8
|
+
/**
|
|
9
|
+
* Deliverable-asset upload CLI (#3961 D6).
|
|
10
|
+
*
|
|
11
|
+
* Dev: `pnpm --filter @working-theory/api deliverable:upload -- --site <siteId>
|
|
12
|
+
* --key <key> --file <path> [--content-type <ct>] [--filename <name>]`.
|
|
13
|
+
* Production: `node dist/bin/deliverable-upload.js <same flags>`.
|
|
14
|
+
*
|
|
15
|
+
* No HTTP upload route exists (spec §2.2) — this CLI is the sole write path
|
|
16
|
+
* for `DeliverableAsset` rows, run by the operator on their own machine/CI,
|
|
17
|
+
* never by a customer or agent request. Re-upload (same siteId + key)
|
|
18
|
+
* REPLACES the stored bytes (upsert) — the config's `assetKey` reference
|
|
19
|
+
* never changes, so a content update is a re-run of this command.
|
|
20
|
+
*
|
|
21
|
+
* The 20 MB cap is a CLI guard, not a schema constraint (Postgres `bytea`
|
|
22
|
+
* has no practical limit at launch volumes) — it keeps the DB-storage
|
|
23
|
+
* choice (D1) honest until the blob-storage upgrade path is taken.
|
|
24
|
+
*/
|
|
25
|
+
import { readFileSync, statSync } from "node:fs";
|
|
26
|
+
import { basename } from "node:path";
|
|
27
|
+
|
|
28
|
+
import { prisma } from "../lib/prisma.js";
|
|
29
|
+
|
|
30
|
+
const MAX_BYTES = 20 * 1024 * 1024; // 20 MB (D6)
|
|
31
|
+
const DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
|
32
|
+
|
|
33
|
+
type ParsedArgs = {
|
|
34
|
+
siteId?: string | undefined;
|
|
35
|
+
key?: string | undefined;
|
|
36
|
+
file?: string | undefined;
|
|
37
|
+
contentType?: string | undefined;
|
|
38
|
+
filename?: string | undefined;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** Minimal `--flag value` parser — no external dependency for a 5-flag CLI. */
|
|
42
|
+
function parseArgs(argv: string[]): ParsedArgs {
|
|
43
|
+
const out: ParsedArgs = {};
|
|
44
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
45
|
+
const flag = argv[i];
|
|
46
|
+
const value = argv[i + 1];
|
|
47
|
+
if (flag === "--site") out.siteId = value;
|
|
48
|
+
else if (flag === "--key") out.key = value;
|
|
49
|
+
else if (flag === "--file") out.file = value;
|
|
50
|
+
else if (flag === "--content-type") out.contentType = value;
|
|
51
|
+
else if (flag === "--filename") out.filename = value;
|
|
52
|
+
else continue;
|
|
53
|
+
i += 1;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function main(): Promise<void> {
|
|
59
|
+
const args = parseArgs(process.argv.slice(2));
|
|
60
|
+
|
|
61
|
+
if (!args.siteId || !args.key || !args.file) {
|
|
62
|
+
console.error(
|
|
63
|
+
"[deliverable-upload] usage: --site <siteId> --key <key> --file <path> " +
|
|
64
|
+
"[--content-type <ct>] [--filename <name>]",
|
|
65
|
+
);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const stat = statSync(args.file);
|
|
71
|
+
if (stat.size > MAX_BYTES) {
|
|
72
|
+
console.error(
|
|
73
|
+
`[deliverable-upload] refused: ${args.file} is ${stat.size} bytes, ` +
|
|
74
|
+
`exceeds the ${MAX_BYTES}-byte (20 MB) cap`,
|
|
75
|
+
);
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const bytes = readFileSync(args.file);
|
|
81
|
+
const filename = args.filename ?? basename(args.file);
|
|
82
|
+
const contentType = args.contentType ?? DEFAULT_CONTENT_TYPE;
|
|
83
|
+
|
|
84
|
+
const row = await prisma.deliverableAsset.upsert({
|
|
85
|
+
where: { siteId_key: { siteId: args.siteId, key: args.key } },
|
|
86
|
+
create: {
|
|
87
|
+
siteId: args.siteId,
|
|
88
|
+
key: args.key,
|
|
89
|
+
filename,
|
|
90
|
+
contentType,
|
|
91
|
+
bytes,
|
|
92
|
+
size: stat.size,
|
|
93
|
+
},
|
|
94
|
+
update: {
|
|
95
|
+
filename,
|
|
96
|
+
contentType,
|
|
97
|
+
bytes,
|
|
98
|
+
size: stat.size,
|
|
99
|
+
},
|
|
100
|
+
select: { key: true },
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
console.log(`[deliverable-upload] uploaded key="${row.key}"`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
main().catch((err: unknown) => {
|
|
107
|
+
// Belt-and-suspenders (mirrors abandon-sweep.ts) — main() has no
|
|
108
|
+
// internal catch of its own, so an unexpected throw (a bad DB
|
|
109
|
+
// connection, a filesystem error mid-read) still exits non-zero with a
|
|
110
|
+
// structured message rather than an unhandled-rejection crash.
|
|
111
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
112
|
+
console.error(`[deliverable-upload] unexpected_error: ${message}`);
|
|
113
|
+
process.exitCode = 1;
|
|
114
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; the underlying
|
|
3
|
+
runWaitlistFollowUpSweep logic is unit-tested in
|
|
4
|
+
services/__tests__/waitlist-followup.test.ts. Mirrors abandon-sweep.ts's
|
|
5
|
+
coverage-ignore rationale — real entry-point semantics run the compiled
|
|
6
|
+
dist directly, on the operator's own cron/scheduler cadence (D1: no
|
|
7
|
+
queue/timer infrastructure in this repo — an external scheduler runs this
|
|
8
|
+
command on whatever cadence the deployment chooses). */
|
|
9
|
+
/**
|
|
10
|
+
* Waitlist follow-up sweep CLI entry (#4732 D1).
|
|
11
|
+
*
|
|
12
|
+
* Dev: `pnpm --filter @working-theory/api followup:sweep` (tsx, this file).
|
|
13
|
+
* Production: `node dist/bin/followup-sweep.js` (the compiled entry, run by
|
|
14
|
+
* any external scheduler — Vercel Cron, GitHub Actions cron, plain crontab).
|
|
15
|
+
* The sweep is stateless and idempotent (the `waitlist_followup_sends`
|
|
16
|
+
* `@@unique([leadId, followUpKey])` guarantee), so overlap or a missed tick
|
|
17
|
+
* is harmless — the offset window is data, not a timer.
|
|
18
|
+
*/
|
|
19
|
+
import { runWaitlistFollowUpSweep } from "../services/waitlist-followup.js";
|
|
20
|
+
|
|
21
|
+
async function main(): Promise<void> {
|
|
22
|
+
const result = await runWaitlistFollowUpSweep();
|
|
23
|
+
|
|
24
|
+
if (!result.ok) {
|
|
25
|
+
console.error(
|
|
26
|
+
`[followup-sweep] ${result.error.kind}: ${result.error.message}`,
|
|
27
|
+
);
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(`[followup-sweep] ${JSON.stringify(result.summary)}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch((err: unknown) => {
|
|
36
|
+
// Belt-and-suspenders (mirrors abandon-sweep.ts): runWaitlistFollowUpSweep
|
|
37
|
+
// already catches internally and returns a structured `unexpected_error`
|
|
38
|
+
// result, so this path is unreachable in practice — it exists only to
|
|
39
|
+
// prevent a bare unhandled-rejection crash if `main` itself ever throws
|
|
40
|
+
// before/around that call.
|
|
41
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
42
|
+
console.error(`[followup-sweep] unexpected_error: ${message}`);
|
|
43
|
+
process.exitCode = 1;
|
|
44
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; the underlying runListingCsvSweep
|
|
3
|
+
logic is unit-tested in services/__tests__/listing-csv-sweep.test.ts.
|
|
4
|
+
Mirrors followup-sweep.ts's coverage-ignore rationale — real entry-point
|
|
5
|
+
semantics run the compiled dist directly, on the operator's own
|
|
6
|
+
cron/scheduler cadence (D1: no queue/timer infrastructure in this repo —
|
|
7
|
+
an external scheduler runs this command on whatever cadence the deployment
|
|
8
|
+
chooses). */
|
|
9
|
+
/**
|
|
10
|
+
* Weekly founder-CSV sweep CLI entry (#5001).
|
|
11
|
+
*
|
|
12
|
+
* Dev: `pnpm --filter @working-theory/api listing-csv:sweep` (tsx, this file).
|
|
13
|
+
* Production: `node dist/bin/listing-csv-sweep.js` (the compiled entry, run by
|
|
14
|
+
* any external scheduler — Vercel Cron, GitHub Actions cron, plain crontab).
|
|
15
|
+
* The consumer schedules this WEEKLY; this repo adds no cron of its own.
|
|
16
|
+
*
|
|
17
|
+
* The sweep is stateless and idempotent: a listing with no `WaitlistScore`
|
|
18
|
+
* newer than its last `ListingCsvSend` sends nothing, so an extra tick is a
|
|
19
|
+
* no-op and a missed tick simply widens the next CSV's window.
|
|
20
|
+
*/
|
|
21
|
+
import { runListingCsvSweep } from "../services/listing-csv-sweep.js";
|
|
22
|
+
|
|
23
|
+
async function main(): Promise<void> {
|
|
24
|
+
const result = await runListingCsvSweep();
|
|
25
|
+
|
|
26
|
+
if (!result.ok) {
|
|
27
|
+
console.error(
|
|
28
|
+
`[listing-csv-sweep] ${result.error.kind}: ${result.error.message}`,
|
|
29
|
+
);
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(`[listing-csv-sweep] ${JSON.stringify(result.summary)}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
main().catch((err: unknown) => {
|
|
38
|
+
// Belt-and-suspenders (mirrors followup-sweep.ts): runListingCsvSweep
|
|
39
|
+
// already catches internally and returns a structured `unexpected_error`
|
|
40
|
+
// result, so this path is unreachable in practice — it exists only to
|
|
41
|
+
// prevent a bare unhandled-rejection crash if `main` itself ever throws
|
|
42
|
+
// before/around that call.
|
|
43
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
44
|
+
console.error(`[listing-csv-sweep] unexpected_error: ${message}`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; the underlying seedFlowPresets logic
|
|
3
|
+
is unit-tested in services/__tests__/flow-engine.test.ts. Mirrors
|
|
4
|
+
bin/abandon-sweep.ts's coverage-ignore rationale — real entry-point
|
|
5
|
+
semantics run the compiled dist directly. */
|
|
6
|
+
/**
|
|
7
|
+
* Flow-preset seed CLI entry (#3958 §3.3).
|
|
8
|
+
*
|
|
9
|
+
* Writes the three static capture presets (form, waitlist, lead-magnet —
|
|
10
|
+
* `@working-theory/database/flows/presets`) through the existing validated
|
|
11
|
+
* `upsertFlowDefinition` path, for the current site (`currentSiteId()`,
|
|
12
|
+
* `lib/site.ts`) — the same site id the `/v1/flows/*` routes resolve against,
|
|
13
|
+
* so a preset is never written somewhere the routes can't find it.
|
|
14
|
+
*
|
|
15
|
+
* Dev: `pnpm --filter @working-theory/api seed:presets` (tsx, this file).
|
|
16
|
+
* Production: `node dist/bin/seed-presets.js` (the compiled entry, run once
|
|
17
|
+
* per site by the operator — idempotent: `upsertFlowDefinition` upserts on
|
|
18
|
+
* `[siteId, slug]`, so a re-run overwrites cleanly rather than duplicating).
|
|
19
|
+
*
|
|
20
|
+
* This entry point is the placement chosen for #3958's operator-facing
|
|
21
|
+
* invocation (spec §3.3 / §7 item 1 — the implementer's choice, both
|
|
22
|
+
* placements bounded and reversible): `apps/api/src/bin/` already hosts
|
|
23
|
+
* exactly this shape of one-off operator command (`abandon-sweep.ts`), so it
|
|
24
|
+
* is the closer fit to "the existing apps/api CLI surface" than adding
|
|
25
|
+
* argv-verb parsing to `cli.ts`, which today does nothing but bootstrap the
|
|
26
|
+
* long-running server.
|
|
27
|
+
*/
|
|
28
|
+
import { FLOW_PRESETS } from "@working-theory/database/flows/presets";
|
|
29
|
+
|
|
30
|
+
import { currentSiteId } from "../lib/site.js";
|
|
31
|
+
import { seedFlowPresets } from "../services/flow-engine.js";
|
|
32
|
+
|
|
33
|
+
async function main(): Promise<void> {
|
|
34
|
+
const siteId = currentSiteId();
|
|
35
|
+
const result = await seedFlowPresets(siteId, FLOW_PRESETS);
|
|
36
|
+
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
console.error(
|
|
39
|
+
`[seed-presets] ${result.error.kind}: ${result.error.message} (seeded before failure: ${result.seeded.join(", ") || "none"})`,
|
|
40
|
+
);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(
|
|
46
|
+
`[seed-presets] seeded for site "${siteId}": ${result.seeded.join(", ")}`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
main().catch((err: unknown) => {
|
|
51
|
+
// Belt-and-suspenders, mirroring abandon-sweep.ts: seedFlowPresets already
|
|
52
|
+
// returns a structured failure rather than throwing, so this path exists
|
|
53
|
+
// only to prevent a bare unhandled-rejection crash if `main` itself ever
|
|
54
|
+
// throws before/around that call.
|
|
55
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
56
|
+
console.error(`[seed-presets] unexpected_error: ${message}`);
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; the underlying seedWaitlistExperiments
|
|
3
|
+
logic is unit-tested in services/__tests__/waitlist-experiments.test.ts.
|
|
4
|
+
Mirrors bin/seed-presets.ts's coverage-ignore rationale. */
|
|
5
|
+
/**
|
|
6
|
+
* Waitlist-experiment seed CLI entry (#4661 D5).
|
|
7
|
+
*
|
|
8
|
+
* Reads one or more experiment-config JSON paths from argv, resolves any
|
|
9
|
+
* `questionSetRef` / `scoringRef` / `sourceTrackingRef` path (relative to the
|
|
10
|
+
* config file) into the embedded objects, and writes them through the
|
|
11
|
+
* existing validated `seedWaitlistExperiments` path, for the current site
|
|
12
|
+
* (`currentSiteId()`, `lib/site.ts`) — the same bootstrap shape as
|
|
13
|
+
* `seed-presets.ts`.
|
|
14
|
+
*
|
|
15
|
+
* `seedWaitlistExperiments` does MORE than write `waitlist_experiments`
|
|
16
|
+
* (#4726): for each config it also compiles + upserts one `flow_definitions`
|
|
17
|
+
* row per `waitlists[]` entry (`materializeWaitlistFlows`,
|
|
18
|
+
* `waitlist-experiments.ts`) — the step `GET /v1/flows/:flowSlug`
|
|
19
|
+
* (`serveFlow`, `flow-engine.ts`) actually reads. A single run of this bin
|
|
20
|
+
* is therefore sufficient to make every declared waitlist servable; a
|
|
21
|
+
* compile failure (`unknown_waitlist` / `unsupported_by_engine`) or a
|
|
22
|
+
* `flow_definitions` write failure exits this process non-zero, naming the
|
|
23
|
+
* failing waitlist key, and writes no `flow_definitions` row for it.
|
|
24
|
+
*
|
|
25
|
+
* Dev: `pnpm --filter @working-theory/api tsx src/bin/seed-waitlist-experiments.ts <config.json>...`
|
|
26
|
+
* Production: `node dist/bin/seed-waitlist-experiments.js <config.json>...` —
|
|
27
|
+
* idempotent (`upsertWaitlistExperiment` upserts on `[siteId, key]`;
|
|
28
|
+
* `upsertFlowDefinition` upserts on `[siteId, slug]`).
|
|
29
|
+
*/
|
|
30
|
+
import { readFileSync } from "node:fs";
|
|
31
|
+
import { dirname, resolve } from "node:path";
|
|
32
|
+
|
|
33
|
+
import { currentSiteId } from "../lib/site.js";
|
|
34
|
+
import { seedWaitlistExperiments } from "../services/waitlist-experiments.js";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A `*Ref` field on the config is a path RELATIVE to the config file (D5),
|
|
38
|
+
* mapped to the embedded field name `waitlistExperimentConfigSchema`
|
|
39
|
+
* actually declares. An EXPLICIT map, not a `Ref$` suffix strip —
|
|
40
|
+
* `sourceTrackingRef` embeds as `tracking` (not `sourceTracking`), which a
|
|
41
|
+
* generic strip gets wrong (code-review finding, #4661).
|
|
42
|
+
*/
|
|
43
|
+
const REF_FIELD_MAP: Record<string, string> = {
|
|
44
|
+
questionSetRef: "questionSet",
|
|
45
|
+
scoringRef: "scoring",
|
|
46
|
+
sourceTrackingRef: "tracking",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function readJson(path: string): unknown {
|
|
50
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve every `*Ref` path on a raw config object relative to `configPath`
|
|
55
|
+
* into the embedded object it names, mirroring the site-plan projection's
|
|
56
|
+
* config-time `*Ref` convention (D5/D7) — the runtime never reads these
|
|
57
|
+
* paths; this bin resolves them once, at seed time.
|
|
58
|
+
*/
|
|
59
|
+
function resolveConfigRefs(raw: unknown, configPath: string): unknown {
|
|
60
|
+
if (typeof raw !== "object" || raw === null) return raw;
|
|
61
|
+
const resolved: Record<string, unknown> = { ...(raw as Record<string, unknown>) };
|
|
62
|
+
const base = dirname(configPath);
|
|
63
|
+
for (const [field, embeddedField] of Object.entries(REF_FIELD_MAP)) {
|
|
64
|
+
const value = resolved[field];
|
|
65
|
+
if (typeof value === "string") {
|
|
66
|
+
resolved[embeddedField] = readJson(resolve(base, value));
|
|
67
|
+
delete resolved[field];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return resolved;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function main(): Promise<void> {
|
|
74
|
+
const configPaths = process.argv.slice(2);
|
|
75
|
+
if (configPaths.length === 0) {
|
|
76
|
+
console.error("[seed-waitlist-experiments] usage: <config.json>...");
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const siteId = currentSiteId();
|
|
82
|
+
const configs = configPaths.map((path) =>
|
|
83
|
+
resolveConfigRefs(readJson(path), path),
|
|
84
|
+
);
|
|
85
|
+
const result = await seedWaitlistExperiments(siteId, configs);
|
|
86
|
+
|
|
87
|
+
if (!result.ok) {
|
|
88
|
+
console.error(
|
|
89
|
+
`[seed-waitlist-experiments] ${result.error.kind}: ${result.error.message} (seeded before failure: ${result.seeded.join(", ") || "none"})`,
|
|
90
|
+
);
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(
|
|
96
|
+
`[seed-waitlist-experiments] seeded for site "${siteId}": ${result.seeded.join(", ")}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main().catch((err: unknown) => {
|
|
101
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
102
|
+
console.error(`[seed-waitlist-experiments] unexpected_error: ${message}`);
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* istanbul ignore file -- CLI bootstrap; the underlying cleanupAbandonedSessions
|
|
3
|
+
logic is unit-tested in services/__tests__/flow-engine.test.ts. Mirrors
|
|
4
|
+
abandon-sweep.ts's coverage-ignore rationale — real entry-point semantics
|
|
5
|
+
run the compiled dist directly, on the operator's own cron/scheduler
|
|
6
|
+
cadence (no queue/timer infrastructure in this repo — an external
|
|
7
|
+
scheduler runs this command on whatever cadence the deployment
|
|
8
|
+
chooses). */
|
|
9
|
+
/**
|
|
10
|
+
* FlowSession retention/cleanup sweep CLI entry (#3974 AC3).
|
|
11
|
+
*
|
|
12
|
+
* Dev: `pnpm --filter @working-theory/api retention:sweep` (tsx, this file).
|
|
13
|
+
* Production: `node dist/bin/session-retention-sweep.js` (the compiled
|
|
14
|
+
* entry, run by any external scheduler — Vercel Cron, GitHub Actions cron,
|
|
15
|
+
* plain crontab). Deletes abandoned FlowSession rows past the retention
|
|
16
|
+
* window (default 90 days) — see `cleanupAbandonedSessions`'s own doc
|
|
17
|
+
* comment in ../services/flow-engine.ts for the full policy + its #3962
|
|
18
|
+
* abandon-email coordination.
|
|
19
|
+
*/
|
|
20
|
+
import { cleanupAbandonedSessions } from "../services/flow-engine.js";
|
|
21
|
+
|
|
22
|
+
async function main(): Promise<void> {
|
|
23
|
+
const result = await cleanupAbandonedSessions();
|
|
24
|
+
|
|
25
|
+
if (!result.ok) {
|
|
26
|
+
console.error(
|
|
27
|
+
`[session-retention-sweep] ${result.error.kind}: ${result.error.message}`,
|
|
28
|
+
);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`[session-retention-sweep] deleted=${result.deleted}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main().catch((err: unknown) => {
|
|
37
|
+
// cleanupAbandonedSessions only returns a structured error for the
|
|
38
|
+
// DB-not-configured case (requireDb's guard) — a genuine prisma/DB
|
|
39
|
+
// exception propagates as a rejected promise, exactly like every other
|
|
40
|
+
// flow-engine.ts function (none of them wrap unexpected DB errors
|
|
41
|
+
// internally). This is that failure's landing spot, so it degrades to a
|
|
42
|
+
// clean process-exit rather than a bare unhandled-rejection crash.
|
|
43
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
44
|
+
console.error(`[session-retention-sweep] unexpected_error: ${message}`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
});
|
|
@@ -15,16 +15,10 @@ import { start } from './index.js';
|
|
|
15
15
|
// Only start if this is the main module
|
|
16
16
|
// Check if executed file matches current file using import.meta.url
|
|
17
17
|
if (process.argv[1]) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
const currentFileUrl = import.meta.url;
|
|
24
|
-
const executedFileUrl = pathToFileURL(process.argv[1]).href;
|
|
25
|
-
|
|
26
|
-
if (currentFileUrl === executedFileUrl) {
|
|
27
|
-
void start();
|
|
28
|
-
}
|
|
18
|
+
const currentFileUrl = import.meta.url;
|
|
19
|
+
const executedFileUrl = pathToFileURL(process.argv[1]).href;
|
|
20
|
+
|
|
21
|
+
if (currentFileUrl === executedFileUrl) {
|
|
22
|
+
void start();
|
|
29
23
|
}
|
|
30
24
|
}
|
|
@@ -21,6 +21,24 @@ export interface Config {
|
|
|
21
21
|
// Stripe — consumed by apps/api/src/lib/stripe.ts via @working-theory/stripe-client wrapper
|
|
22
22
|
STRIPE_SECRET_KEY?: string;
|
|
23
23
|
STRIPE_WEBHOOK_SECRET?: string;
|
|
24
|
+
|
|
25
|
+
// Slack — the project-listings approve/reject workflow (#4999). Consumed
|
|
26
|
+
// by services/slack-notify.ts (bot token + channel) and
|
|
27
|
+
// routes/slack/actions.ts (signing secret, for X-Slack-Signature
|
|
28
|
+
// verification). All three optional; absent means "Slack off" — a create
|
|
29
|
+
// still succeeds, it just skips the notification.
|
|
30
|
+
AILK_SLACK_BOT_TOKEN?: string;
|
|
31
|
+
AILK_SLACK_SIGNING_SECRET?: string;
|
|
32
|
+
AILK_SLACK_CHANNEL_ID?: string;
|
|
33
|
+
|
|
34
|
+
// GitHub issue filing — the approve-time build-issue workflow (#5000).
|
|
35
|
+
// Consumed by services/project-listing-issue.ts: AILK_GITHUB_REPO is the
|
|
36
|
+
// site's own `owner/name` (never this repo); AILK_GITHUB_TOKEN is a
|
|
37
|
+
// fine-grained token scoped to `issues:write` on that one repo. Both
|
|
38
|
+
// optional; absent means "filing off" — approve still succeeds, and the
|
|
39
|
+
// row's issueUrl stays null for a later retry via the PATCH route.
|
|
40
|
+
AILK_GITHUB_REPO?: string;
|
|
41
|
+
AILK_GITHUB_TOKEN?: string;
|
|
24
42
|
}
|
|
25
43
|
|
|
26
44
|
function validateConfig(): Config {
|
|
@@ -50,6 +68,23 @@ function validateConfig(): Config {
|
|
|
50
68
|
...(process.env.STRIPE_WEBHOOK_SECRET !== undefined && {
|
|
51
69
|
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
|
|
52
70
|
}),
|
|
71
|
+
|
|
72
|
+
...(process.env.AILK_SLACK_BOT_TOKEN !== undefined && {
|
|
73
|
+
AILK_SLACK_BOT_TOKEN: process.env.AILK_SLACK_BOT_TOKEN,
|
|
74
|
+
}),
|
|
75
|
+
...(process.env.AILK_SLACK_SIGNING_SECRET !== undefined && {
|
|
76
|
+
AILK_SLACK_SIGNING_SECRET: process.env.AILK_SLACK_SIGNING_SECRET,
|
|
77
|
+
}),
|
|
78
|
+
...(process.env.AILK_SLACK_CHANNEL_ID !== undefined && {
|
|
79
|
+
AILK_SLACK_CHANNEL_ID: process.env.AILK_SLACK_CHANNEL_ID,
|
|
80
|
+
}),
|
|
81
|
+
|
|
82
|
+
...(process.env.AILK_GITHUB_REPO !== undefined && {
|
|
83
|
+
AILK_GITHUB_REPO: process.env.AILK_GITHUB_REPO,
|
|
84
|
+
}),
|
|
85
|
+
...(process.env.AILK_GITHUB_TOKEN !== undefined && {
|
|
86
|
+
AILK_GITHUB_TOKEN: process.env.AILK_GITHUB_TOKEN,
|
|
87
|
+
}),
|
|
53
88
|
};
|
|
54
89
|
}
|
|
55
90
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paid-module presence — the registration-grain signal used by `server.ts`
|
|
3
|
+
* to decide whether a paid module's routes (and their imports) are wired
|
|
4
|
+
* into this build (S1, #5088).
|
|
5
|
+
*
|
|
6
|
+
* `AILK_ENABLED_MODULES` is a comma-separated allowlist (e.g.
|
|
7
|
+
* `"multi-tenant,scheduling"`). Unset means "every module on" — today's
|
|
8
|
+
* behavior, unchanged for every existing deployment; an explicit empty
|
|
9
|
+
* string (`""`) means "no paid modules" (the OSS-strip build target). This
|
|
10
|
+
* mirrors `shouldMountTestAuth()`'s fail-open-by-default / explicit-opt-in
|
|
11
|
+
* shape elsewhere in this file's sibling config.
|
|
12
|
+
*
|
|
13
|
+
* Recognized module keys: `docs`, `multi-tenant`, `scheduling` (the
|
|
14
|
+
* `ModuleName` vocabulary `packages/create-ailk/src/module-architecture.ts`
|
|
15
|
+
* already models via `MODULE_SLICES`) plus `content-write` — the Pro
|
|
16
|
+
* content-write surface (`create`/`update`/`delete` under
|
|
17
|
+
* `apps/api/src/routes/content/`). `content-write` is intentionally NOT a
|
|
18
|
+
* `MODULE_SLICES` entry: it is not (yet) a `create-ailk --modules`
|
|
19
|
+
* selector — a customer never opts into it at scaffold time, it is a
|
|
20
|
+
* license-tier line drawn inside the single `apps/api` app — so it stays a
|
|
21
|
+
* local registration flag here rather than widening the create-ailk module
|
|
22
|
+
* vocabulary. This function does not validate its input against that list;
|
|
23
|
+
* it is a thin string-set reader so `apps/api` has no reason to import
|
|
24
|
+
* create-ailk's module types (outside its package allowlist anyway).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
function enabledModules(): Set<string> | undefined {
|
|
28
|
+
const raw = process.env.AILK_ENABLED_MODULES;
|
|
29
|
+
if (raw === undefined) return undefined; // undefined sentinel = "all enabled"
|
|
30
|
+
return new Set(
|
|
31
|
+
raw
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((m) => m.trim())
|
|
34
|
+
.filter(Boolean),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Whether the named paid module's routes should register on this build/boot. */
|
|
39
|
+
export function isModuleEnabled(moduleName: string): boolean {
|
|
40
|
+
const enabled = enabledModules();
|
|
41
|
+
if (enabled === undefined) return true;
|
|
42
|
+
return enabled.has(moduleName);
|
|
43
|
+
}
|
|
@@ -10,6 +10,17 @@ const MockPrismaClient = jest.fn().mockImplementation((options) => ({
|
|
|
10
10
|
userData: {},
|
|
11
11
|
}));
|
|
12
12
|
|
|
13
|
+
// #4663 D6 — flow-engine.ts imports the real `Prisma` runtime namespace (a
|
|
14
|
+
// VALUE, not just a type) to write the `Prisma.JsonNull` sentinel on a
|
|
15
|
+
// nullable Json column reset. Real distinct sentinel objects, matching the
|
|
16
|
+
// generated client's own runtime shape closely enough for identity checks
|
|
17
|
+
// (`toBe(Prisma.JsonNull)`) in tests.
|
|
18
|
+
const Prisma = {
|
|
19
|
+
JsonNull: Symbol("Prisma.JsonNull"),
|
|
20
|
+
DbNull: Symbol("Prisma.DbNull"),
|
|
21
|
+
};
|
|
22
|
+
|
|
13
23
|
module.exports = {
|
|
14
24
|
PrismaClient: MockPrismaClient,
|
|
25
|
+
Prisma,
|
|
15
26
|
};
|