create-ailk 0.2.0 → 0.4.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/component-catalog.md +50 -53
- package/dist/cli.js +19 -9
- package/dist/lib/apply-module-patches.d.ts +47 -0
- package/dist/lib/apply-module-patches.js +370 -0
- package/dist/lib/extract-module-bundle.d.ts +51 -3
- package/dist/lib/extract-module-bundle.js +327 -28
- package/dist/lib/fetch-module.d.ts +3 -38
- package/dist/lib/fetch-module.js +26 -8
- package/dist/lib/fetch-template.d.ts +20 -0
- package/dist/lib/fetch-template.js +129 -0
- package/dist/lib/module-license-gate.d.ts +10 -0
- package/dist/lib/module-license-gate.js +13 -4
- package/dist/lib/paid-paths.d.ts +16 -0
- package/dist/lib/paid-paths.js +90 -0
- package/dist/module-architecture.d.ts +197 -23
- package/dist/module-architecture.js +820 -25
- package/dist/parse-args.d.ts +9 -2
- package/dist/parse-args.js +46 -1
- package/dist/programmatic.d.ts +28 -2
- package/dist/programmatic.js +115 -8
- package/dist/surfaces.d.ts +12 -36
- package/dist/surfaces.js +77 -5
- package/dist/sync-routes.js +31 -1
- package/dist/template-manifest.d.ts +92 -0
- package/dist/template-manifest.js +168 -0
- package/dist/template-names.d.ts +41 -0
- package/dist/template-names.js +44 -0
- package/package.json +3 -2
- package/site-templates/marketing-site-free/ailk-template.json +8 -0
- package/site-templates/marketing-site-free/content/en/Pricing/pricing.mdx +103 -0
- package/site-templates/marketing-site-free/content/en/PrivacyPage/privacy.mdx +79 -0
- package/site-templates/marketing-site-free/content/en/TermsPage/terms.mdx +80 -0
- package/site-templates/marketing-site-free/provenance.json +4 -0
- package/templates/.claude/agents/web.md +2 -3
- package/templates/.claude/rules/architecture.md +5 -5
- package/templates/.claude/skills/README.md +2 -1
- package/templates/.env.example +21 -9
- package/templates/CONVENTIONS.md +6 -7
- package/templates/apps/api/.env.example +9 -0
- package/templates/apps/api/CLAUDE.md +33 -5
- package/templates/apps/api/package.json +0 -1
- package/templates/apps/api/src/__tests__/cors.test.ts +195 -0
- package/templates/apps/api/src/__tests__/module-exclusion.test.ts +60 -2
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +159 -0
- package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +166 -0
- package/templates/apps/api/src/config/__tests__/modules.test.ts +76 -0
- package/templates/apps/api/src/config/index.ts +19 -0
- package/templates/apps/api/src/config/modules.ts +12 -14
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -0
- package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +89 -0
- package/templates/apps/api/src/lib/slice-load.ts +90 -0
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +52 -32
- package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +182 -0
- package/templates/apps/api/src/openapi/__tests__/surface-drift.test.ts +293 -0
- package/templates/apps/api/src/openapi/index.ts +9 -3
- package/templates/apps/api/src/openapi/spec.ts +505 -65
- package/templates/apps/api/src/openapi/surface-drift.ts +195 -0
- package/templates/apps/api/src/routes/content/__tests__/create.test.ts +14 -0
- package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +14 -0
- package/templates/apps/api/src/routes/content/__tests__/update.test.ts +14 -0
- package/templates/apps/api/src/routes/content/index.ts +38 -11
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +17 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +17 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +796 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +10 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +38 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +814 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +10 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +24 -0
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +17 -0
- package/templates/apps/api/src/routes/project-listings/index.ts +37 -10
- package/templates/apps/api/src/routes/project-listings/me.ts +10 -0
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +5 -0
- package/templates/apps/api/src/routes/project-listings/public.ts +5 -0
- package/templates/apps/api/src/routes/project-listings/respond.ts +11 -0
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +5 -0
- package/templates/apps/api/src/routes/project-listings/start.ts +30 -0
- package/templates/apps/api/src/routes/project-listings/submit.ts +5 -0
- package/templates/apps/api/src/routes/project-listings/verify-email.ts +150 -0
- package/templates/apps/api/src/server.ts +504 -137
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +10 -0
- package/templates/apps/api/src/services/listing-config.ts +58 -0
- package/templates/apps/api/src/services/project-listing-resume-email.ts +326 -0
- package/templates/apps/api/src/services/project-listings.ts +229 -4
- package/templates/apps/api/src/vercel-handler.ts +60 -26
- package/templates/apps/mcp/.env.example +8 -0
- package/templates/apps/mcp/CLAUDE.md +2 -2
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +21 -0
- package/templates/apps/mcp/__tests__/config/modules.test.ts +78 -0
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +1 -1
- package/templates/apps/mcp/src/config/modules.ts +14 -13
- package/templates/apps/mcp/src/server.ts +8 -4
- package/templates/apps/mcp/src/tools/index.ts +7 -22
- package/templates/apps/web/.env.example +15 -0
- package/templates/apps/web/app/[locale]/(authed)/{waitlist/__tests__ → __tests__}/gate.test.tsx +4 -4
- package/templates/apps/web/app/[locale]/flows/[slug]/FlowStepperClient.tsx +2 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx +2 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.test.tsx +2 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/flow.actions.test.ts +1 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/two-route-tool.test.tsx +1 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +2 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/page.tsx +1 -0
- package/templates/apps/web/app/[locale]/flows/[slug]/start/page.tsx +1 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +40 -0
- package/templates/apps/web/app/[locale]/privacy/page.tsx +40 -0
- package/templates/apps/web/app/[locale]/terms/page.tsx +40 -0
- package/templates/apps/web/app/llms.txt/route.ts +12 -9
- package/templates/apps/web/jest.config.cjs +19 -13
- package/templates/apps/web/lib/__tests__/server-api.test.ts +61 -0
- package/templates/apps/web/lib/server-api.ts +28 -12
- package/templates/apps/web/messages/en.json +58 -0
- package/templates/apps/web/next.config.mjs +1 -3
- package/templates/apps/web/package.json +0 -6
- 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 +6 -3
- package/templates/apps/web/public/lockup-horizontal.svg +4 -0
- package/templates/apps/web/public/logomark.svg +4 -0
- package/templates/apps/web/public/site.webmanifest +2 -2
- package/templates/apps/web/public/wordmark.svg +4 -0
- package/templates/database/CHANGELOG.md +47 -0
- package/templates/database/inbox/schema.prisma +67 -0
- package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +123 -0
- package/templates/database/package.json +1 -1
- package/templates/package.json +1 -1
- package/templates/.claude/skills/scaffold-commerce/SKILL.md +0 -807
- package/templates/.claude/skills/scaffold-commerce/references/lookup-keys-template.md +0 -71
- package/templates/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md +0 -83
- package/templates/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts +0 -370
- package/templates/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts +0 -376
- package/templates/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl +0 -72
- package/templates/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts +0 -471
- package/templates/.claude/skills/scaffold-commerce/templates/portal-route.template.ts +0 -365
- package/templates/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts +0 -60
- package/templates/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts +0 -446
- package/templates/apps/api/src/__tests__/server.test.ts +0 -253
- package/templates/apps/api/src/bin/deliverable-resend.ts +0 -144
- package/templates/apps/api/src/bin/deliverable-upload.ts +0 -114
- package/templates/apps/api/src/bin/followup-sweep.ts +0 -44
- package/templates/apps/api/src/bin/listing-csv-sweep.ts +0 -46
- package/templates/apps/api/src/bin/seed-presets.ts +0 -58
- package/templates/apps/api/src/bin/seed-waitlist-experiments.ts +0 -104
- package/templates/apps/api/src/bin/session-retention-sweep.ts +0 -46
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -74
- package/templates/apps/api/src/lib/stripe.ts +0 -52
- package/templates/apps/api/src/lib/tenant-db.ts +0 -225
- package/templates/apps/api/src/lib/ws-token.ts +0 -91
- package/templates/apps/api/src/middleware/tenant.ts +0 -99
- package/templates/apps/api/src/routes/billing/__tests__/portal.test.ts +0 -450
- package/templates/apps/api/src/routes/billing/__tests__/read.test.ts +0 -262
- package/templates/apps/api/src/routes/billing/__tests__/usage.test.ts +0 -436
- package/templates/apps/api/src/routes/billing/index.ts +0 -36
- package/templates/apps/api/src/routes/billing/portal.ts +0 -182
- package/templates/apps/api/src/routes/billing/read.ts +0 -75
- package/templates/apps/api/src/routes/billing/usage.ts +0 -153
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -687
- package/templates/apps/api/src/routes/checkout/index.ts +0 -13
- package/templates/apps/api/src/routes/checkout/sessions.ts +0 -197
- package/templates/apps/api/src/routes/deliverables/__tests__/index.test.ts +0 -393
- package/templates/apps/api/src/routes/deliverables/index.ts +0 -200
- package/templates/apps/api/src/routes/flow-checkouts/__tests__/index.test.ts +0 -443
- package/templates/apps/api/src/routes/flow-checkouts/index.ts +0 -82
- package/templates/apps/api/src/routes/flows/README.md +0 -147
- package/templates/apps/api/src/routes/flows/__tests__/index.test.ts +0 -752
- package/templates/apps/api/src/routes/flows/__tests__/recommender.test.ts +0 -671
- package/templates/apps/api/src/routes/flows/index.ts +0 -202
- package/templates/apps/api/src/routes/flows/recommender.ts +0 -443
- package/templates/apps/api/src/routes/project-listings/__tests__/copy-edit.test.ts +0 -815
- package/templates/apps/api/src/routes/project-listings/__tests__/me-route-precedence.test.ts +0 -221
- package/templates/apps/api/src/routes/project-listings/__tests__/tenant-isolation.test.ts +0 -566
- package/templates/apps/api/src/routes/project-listings/get.ts +0 -70
- package/templates/apps/api/src/routes/project-listings/list.ts +0 -47
- package/templates/apps/api/src/routes/project-listings/patch.ts +0 -136
- package/templates/apps/api/src/routes/schedule/__tests__/index.test.ts +0 -490
- package/templates/apps/api/src/routes/schedule/index.ts +0 -249
- package/templates/apps/api/src/routes/slack/__tests__/actions.test.ts +0 -385
- package/templates/apps/api/src/routes/slack/actions.ts +0 -177
- package/templates/apps/api/src/routes/slack/index.ts +0 -38
- package/templates/apps/api/src/routes/waitlist-experiments/__tests__/tenant-isolation.test.ts +0 -577
- package/templates/apps/api/src/routes/waitlist-experiments/comparison.ts +0 -78
- package/templates/apps/api/src/routes/waitlist-experiments/index.ts +0 -41
- package/templates/apps/api/src/routes/waitlist-experiments/list.ts +0 -64
- package/templates/apps/api/src/routes/waitlist-experiments/respond.ts +0 -42
- package/templates/apps/api/src/routes/waitlist-experiments/signup.ts +0 -84
- package/templates/apps/api/src/routes/waitlist-experiments/signups.ts +0 -119
- package/templates/apps/api/src/routes/waitlist-signups/__tests__/index.test.ts +0 -238
- package/templates/apps/api/src/routes/waitlist-signups/index.ts +0 -101
- package/templates/apps/api/src/routes/webhooks/README.md +0 -80
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -315
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -247
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -270
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -198
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -633
- package/templates/apps/api/src/routes/webhooks/index.ts +0 -41
- package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -481
- package/templates/apps/api/src/routes/workspaces/__tests__/config-tenant-isolation.test.ts +0 -356
- package/templates/apps/api/src/routes/workspaces/__tests__/tenant-isolation.test.ts +0 -671
- package/templates/apps/api/src/routes/workspaces/config.ts +0 -125
- package/templates/apps/api/src/routes/workspaces/index.ts +0 -194
- package/templates/apps/api/src/routes/workspaces/sessions.ts +0 -218
- package/templates/apps/api/src/services/__tests__/flow-aggregate.test.ts +0 -425
- package/templates/apps/api/src/services/__tests__/flow-engine.test.ts +0 -2840
- package/templates/apps/api/src/services/__tests__/lead-promotion.test.ts +0 -393
- package/templates/apps/api/src/services/__tests__/listing-csv-sweep.test.ts +0 -560
- package/templates/apps/api/src/services/__tests__/listing-promotion.test.ts +0 -684
- package/templates/apps/api/src/services/__tests__/playbook-compile.test.ts +0 -406
- package/templates/apps/api/src/services/__tests__/playbook-render.test.ts +0 -290
- package/templates/apps/api/src/services/__tests__/project-listing-decision.test.ts +0 -736
- package/templates/apps/api/src/services/__tests__/project-listing-flow.test.ts +0 -475
- package/templates/apps/api/src/services/__tests__/project-listing-issue.test.ts +0 -340
- package/templates/apps/api/src/services/__tests__/recommender-capture.test.ts +0 -983
- package/templates/apps/api/src/services/__tests__/tenant-context-cascade.test.ts +0 -71
- package/templates/apps/api/src/services/__tests__/tenant-context.test.ts +0 -379
- package/templates/apps/api/src/services/__tests__/usage-metering.test.ts +0 -768
- package/templates/apps/api/src/services/__tests__/waitlist-dashboard.test.ts +0 -1314
- package/templates/apps/api/src/services/__tests__/waitlist-experiments.test.ts +0 -341
- package/templates/apps/api/src/services/__tests__/waitlist-followup.test.ts +0 -567
- package/templates/apps/api/src/services/__tests__/waitlist-scoring.test.ts +0 -474
- package/templates/apps/api/src/services/__tests__/waitlist-signups.test.ts +0 -354
- package/templates/apps/api/src/services/flow-aggregate.ts +0 -232
- package/templates/apps/api/src/services/flow-checkouts.ts +0 -123
- package/templates/apps/api/src/services/flow-engine.ts +0 -1296
- package/templates/apps/api/src/services/lead-promotion.ts +0 -176
- package/templates/apps/api/src/services/listing-csv-sweep.ts +0 -455
- package/templates/apps/api/src/services/listing-promotion.ts +0 -342
- package/templates/apps/api/src/services/playbook-compile.ts +0 -398
- package/templates/apps/api/src/services/playbook-render.ts +0 -263
- package/templates/apps/api/src/services/project-listing-decision.ts +0 -510
- package/templates/apps/api/src/services/project-listing-flow.ts +0 -426
- package/templates/apps/api/src/services/project-listing-issue.ts +0 -251
- package/templates/apps/api/src/services/recommender-capture.ts +0 -835
- package/templates/apps/api/src/services/scheduling/cal-provider.ts +0 -392
- package/templates/apps/api/src/services/scheduling/index.ts +0 -63
- package/templates/apps/api/src/services/scheduling/types.ts +0 -88
- package/templates/apps/api/src/services/tenant-context.ts +0 -451
- package/templates/apps/api/src/services/usage-metering.ts +0 -699
- package/templates/apps/api/src/services/waitlist-dashboard.ts +0 -947
- package/templates/apps/api/src/services/waitlist-experiments.ts +0 -213
- package/templates/apps/api/src/services/waitlist-followup.ts +0 -486
- package/templates/apps/api/src/services/waitlist-scoring.ts +0 -166
- package/templates/apps/api/src/services/waitlist-signups.ts +0 -165
- package/templates/apps/mcp/__tests__/schedule_tools.test.ts +0 -242
- package/templates/apps/mcp/src/tools/create_booking.ts +0 -58
- package/templates/apps/mcp/src/tools/get_event_meta.ts +0 -55
- package/templates/apps/mcp/src/tools/get_flow.ts +0 -61
- package/templates/apps/mcp/src/tools/list_availability.ts +0 -67
- package/templates/apps/mcp/src/tools/submit_flow_step.ts +0 -83
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx +0 -309
- package/templates/apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx +0 -149
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/comparison.test.tsx +0 -273
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/list.test.tsx +0 -171
- package/templates/apps/web/app/[locale]/(authed)/waitlist/__tests__/signup.test.tsx +0 -179
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx +0 -116
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx +0 -66
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx +0 -61
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx +0 -114
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx +0 -139
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx +0 -85
- package/templates/apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx +0 -67
- package/templates/apps/web/app/[locale]/(authed)/waitlist/page.tsx +0 -179
- package/templates/apps/web/app/[locale]/blog/[[...slug]]/page.tsx +0 -178
- package/templates/apps/web/app/[locale]/dev/purchase/__tests__/actions.test.ts +0 -160
- package/templates/apps/web/app/[locale]/dev/purchase/error.tsx +0 -25
- package/templates/apps/web/app/[locale]/dev/purchase/page.tsx +0 -117
- package/templates/apps/web/app/[locale]/dev/purchase/purchase.actions.ts +0 -58
- package/templates/apps/web/app/[locale]/docs/[[...slug]]/page.tsx +0 -119
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/checkout.actions.test.ts +0 -287
- package/templates/apps/web/app/[locale]/flows/[slug]/checkout.actions.ts +0 -254
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx +0 -532
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx +0 -121
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/ResultsClient.checkout.test.tsx +0 -457
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/__tests__/page.test.tsx +0 -396
- package/templates/apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx +0 -114
- package/templates/apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx +0 -110
- package/templates/apps/web/app/[locale]/projects/apply/__tests__/ListingApplicationClient.test.tsx +0 -96
- package/templates/apps/web/app/[locale]/schedule/__tests__/page.test.tsx +0 -117
- package/templates/apps/web/app/[locale]/schedule/confirmed/__tests__/page.test.tsx +0 -96
- package/templates/apps/web/app/[locale]/schedule/confirmed/page.tsx +0 -92
- package/templates/apps/web/app/[locale]/schedule/page.tsx +0 -82
- package/templates/apps/web/content/en/blog/README.txt +0 -25
- package/templates/apps/web/content/en/docs/index.mdx +0 -28
- package/templates/apps/web/lib/__mocks__/source-server.js +0 -31
- package/templates/apps/web/lib/blog-list-data.ts +0 -95
- package/templates/apps/web/lib/blog-post-data.ts +0 -79
- package/templates/apps/web/lib/source.ts +0 -34
- package/templates/apps/web/public/logomark-dark.svg +0 -4
- package/templates/apps/web/public/logomark-light.svg +0 -4
- package/templates/apps/web/source.config.ts +0 -78
|
@@ -124,27 +124,12 @@ export {
|
|
|
124
124
|
type ScaffoldOutput,
|
|
125
125
|
} from "./scaffold.js";
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
export {
|
|
136
|
-
submitFlowStepInputSchemaForTool,
|
|
137
|
-
submitFlowStepOutputSchema,
|
|
138
|
-
ailkSubmitFlowStep,
|
|
139
|
-
type SubmitFlowStepInput,
|
|
140
|
-
type AilkSubmitFlowStepOutput,
|
|
141
|
-
} from "./submit_flow_step.js";
|
|
142
|
-
|
|
143
|
-
// The scheduling tools (list_availability, get_event_meta, create_booking) are
|
|
144
|
-
// deliberately NOT re-exported here, and neither are the content-write tools
|
|
145
|
-
// (create_page, update_page, delete_page). Both groups are module-conditional
|
|
146
|
-
// slice files (#5182): a re-export from this barrel is a static path into a
|
|
147
|
-
// file the OSS strip removes, which reds the public tree's type-check. They are
|
|
148
|
-
// reached only through `createMcpServer`'s per-module loader in ../server.ts.
|
|
127
|
+
// The scheduling tools (list_availability, get_event_meta, create_booking),
|
|
128
|
+
// the content-write tools (create_page, update_page, delete_page), and the
|
|
129
|
+
// signal-collectors flow tools (get_flow, submit_flow_step) are deliberately
|
|
130
|
+
// NOT re-exported here. All three groups are module-conditional slice files
|
|
131
|
+
// (#5182): a re-export from this barrel is a static path into a file the OSS
|
|
132
|
+
// strip removes, which reds the public tree's type-check. They are reached
|
|
133
|
+
// only through `createMcpServer`'s per-module loader in ../server.ts.
|
|
149
134
|
// The rule this barrel now follows: it re-exports exactly the tools no module
|
|
150
135
|
// gate can remove.
|
|
@@ -26,6 +26,21 @@ CONTENT_BACKEND=mdx
|
|
|
26
26
|
# Same convention as apps/workspace/lib/client-api.ts's identically-named var.
|
|
27
27
|
# Should be apps/api's origin with NO trailing slash (a single trailing
|
|
28
28
|
# slash is stripped before joining, but keep this clean regardless).
|
|
29
|
+
#
|
|
30
|
+
# THIS IS THE ONE BROWSER-SIDE NAME (#5397). All three browser readers of the
|
|
31
|
+
# apps/api origin resolve it from this variable: resolveSubmitUrl
|
|
32
|
+
# (packages/ui, the form blocks above), apps/workspace's client-api, and
|
|
33
|
+
# @working-theory/api-client's getApiBase() — which runs in the browser
|
|
34
|
+
# wherever a "use client" component binds it, e.g. the founder application's
|
|
35
|
+
# ListingApplicationClient. getApiBase() previously read NEXT_PUBLIC_API_URL,
|
|
36
|
+
# a name this file never documented, so a site configured exactly per these
|
|
37
|
+
# docs sent its browser traffic to http://localhost:3001. That name is still
|
|
38
|
+
# honoured as a deprecated fallback; do not set it in a new deployment.
|
|
39
|
+
#
|
|
40
|
+
# The server-side counterpart is AILK_API_URL (see the repo-root .env.example)
|
|
41
|
+
# — deliberately NOT NEXT_PUBLIC_, and it still wins over this one when both
|
|
42
|
+
# are set, so an RSC/Server-Action call can target an internal origin the
|
|
43
|
+
# browser never sees.
|
|
29
44
|
# NEXT_PUBLIC_AILK_API_URL=http://localhost:3002
|
|
30
45
|
|
|
31
46
|
# =============================================================================
|
package/templates/apps/web/app/[locale]/(authed)/{waitlist/__tests__ → __tests__}/gate.test.tsx
RENAMED
|
@@ -24,14 +24,14 @@ jest.mock("next/headers", () => ({
|
|
|
24
24
|
|
|
25
25
|
const mockGetSession = jest.fn();
|
|
26
26
|
// eslint-disable-next-line no-restricted-syntax -- #507: mock-internal rewrite pending; auth.ts's lazy Better-Auth singleton has no HTTP/DB boundary a unit test of the session-branch can mock without standing up Prisma.
|
|
27
|
-
jest.mock("
|
|
27
|
+
jest.mock("../../../../auth", () => ({
|
|
28
28
|
__esModule: true,
|
|
29
29
|
auth: { api: { getSession: (...args: unknown[]) => mockGetSession(...args) } },
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
32
|
const mockGetActiveProviderIds = jest.fn();
|
|
33
33
|
// eslint-disable-next-line no-restricted-syntax -- #507: mock-internal rewrite pending; auth-env.ts is a pure env-introspection module with no external boundary to mock instead.
|
|
34
|
-
jest.mock("
|
|
34
|
+
jest.mock("../../../../lib/auth-env", () => ({
|
|
35
35
|
__esModule: true,
|
|
36
36
|
getActiveProviderIds: () => mockGetActiveProviderIds(),
|
|
37
37
|
}));
|
|
@@ -48,8 +48,8 @@ jest.mock("better-auth/react", () => ({
|
|
|
48
48
|
createAuthClient: () => ({ signIn: { social: mockSignInSocial } }),
|
|
49
49
|
}));
|
|
50
50
|
|
|
51
|
-
import AuthedLayout from "
|
|
52
|
-
import { SignInGate } from "
|
|
51
|
+
import AuthedLayout from "../layout";
|
|
52
|
+
import { SignInGate } from "../sign-in-gate";
|
|
53
53
|
|
|
54
54
|
describe("AuthedLayout — the (authed) session guard", () => {
|
|
55
55
|
beforeEach(() => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oss: false
|
|
1
2
|
"use client";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -53,7 +54,7 @@ import {
|
|
|
53
54
|
type FlowStepperMessages,
|
|
54
55
|
type FlowStepSubmitPayload,
|
|
55
56
|
type FlowStepSubmitResult,
|
|
56
|
-
} from "@working-theory/ui";
|
|
57
|
+
} from "@working-theory/ui/slices/signal-collectors";
|
|
57
58
|
import type { AeoScoreResult, FlowConfig, FlowState } from "@working-theory/validation";
|
|
58
59
|
import {
|
|
59
60
|
deriveFlags,
|
package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/FlowStepperClient.permalink.test.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oss: false
|
|
1
2
|
/**
|
|
2
3
|
* Tests for FlowStepperClient's permalink completion redirect on a
|
|
3
4
|
* `mode:"recommending"` flow (#4770 D1/D7/D12).
|
|
@@ -64,7 +65,7 @@ interface MockFlowStepperProps {
|
|
|
64
65
|
|
|
65
66
|
let captured: MockFlowStepperProps | undefined;
|
|
66
67
|
|
|
67
|
-
jest.mock("@working-theory/ui", () => ({
|
|
68
|
+
jest.mock("@working-theory/ui/slices/signal-collectors", () => ({
|
|
68
69
|
FlowStepper: (props: MockFlowStepperProps) => {
|
|
69
70
|
captured = props;
|
|
70
71
|
return require("react").createElement("div", {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oss: false
|
|
1
2
|
/**
|
|
2
3
|
* Tests for FlowStepperClient's segment-keyed completion redirect (#3960 D5).
|
|
3
4
|
*
|
|
@@ -68,7 +69,7 @@ const PII_PAYLOAD = {
|
|
|
68
69
|
|
|
69
70
|
let capturedOnCompleted: MockFlowStepperProps["onCompleted"];
|
|
70
71
|
|
|
71
|
-
jest.mock("@working-theory/ui", () => ({
|
|
72
|
+
jest.mock("@working-theory/ui/slices/signal-collectors", () => ({
|
|
72
73
|
FlowStepper: (props: MockFlowStepperProps) => {
|
|
73
74
|
capturedOnCompleted = props.onCompleted;
|
|
74
75
|
async function handleSubmit(): Promise<void> {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oss: false
|
|
1
2
|
"use server";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
32
|
import { flows } from "@working-theory/api-client";
|
|
32
|
-
import type { FlowStepSubmitResult } from "@working-theory/ui";
|
|
33
|
+
import type { FlowStepSubmitResult } from "@working-theory/ui/slices/signal-collectors";
|
|
33
34
|
import {
|
|
34
35
|
flowSlugSchema,
|
|
35
36
|
submitFlowStepInputSchema,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Pricing page. Reads the Pricing MDX frontmatter, renders sections via
|
|
2
|
+
// SectionRenderer, and emits a JSON-LD <script>.
|
|
3
|
+
import type {
|
|
4
|
+
getMdxSource as defaultGetMdxSource,
|
|
5
|
+
getPageSections as defaultGetPageSections} from "@working-theory/page-renderer";
|
|
6
|
+
import {
|
|
7
|
+
renderPage,
|
|
8
|
+
renderPageMetadata
|
|
9
|
+
} from "@working-theory/page-renderer";
|
|
10
|
+
import type { Metadata } from "next";
|
|
11
|
+
import type { ReactElement } from "react";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
params: Promise<{ locale: string }>;
|
|
15
|
+
getMdxSource?: typeof defaultGetMdxSource;
|
|
16
|
+
getPageSections?: typeof defaultGetPageSections;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata({
|
|
20
|
+
params,
|
|
21
|
+
}: Pick<Props, "params">): Promise<Metadata> {
|
|
22
|
+
const { locale } = await params;
|
|
23
|
+
return renderPageMetadata({ type: "Pricing", slug: "pricing", locale });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function Page({
|
|
27
|
+
params,
|
|
28
|
+
getMdxSource,
|
|
29
|
+
getPageSections,
|
|
30
|
+
}: Props): Promise<ReactElement> {
|
|
31
|
+
const { locale } = await params;
|
|
32
|
+
return renderPage({
|
|
33
|
+
type: "Pricing",
|
|
34
|
+
slug: "pricing",
|
|
35
|
+
locale,
|
|
36
|
+
translationsNamespace: "pricing",
|
|
37
|
+
...(getMdxSource !== undefined && { getMdxSource }),
|
|
38
|
+
...(getPageSections !== undefined && { getPageSections }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Privacy page. Reads the PrivacyPage MDX frontmatter, renders sections via
|
|
2
|
+
// SectionRenderer, and emits a JSON-LD <script>.
|
|
3
|
+
import type {
|
|
4
|
+
getMdxSource as defaultGetMdxSource,
|
|
5
|
+
getPageSections as defaultGetPageSections} from "@working-theory/page-renderer";
|
|
6
|
+
import {
|
|
7
|
+
renderPage,
|
|
8
|
+
renderPageMetadata
|
|
9
|
+
} from "@working-theory/page-renderer";
|
|
10
|
+
import type { Metadata } from "next";
|
|
11
|
+
import type { ReactElement } from "react";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
params: Promise<{ locale: string }>;
|
|
15
|
+
getMdxSource?: typeof defaultGetMdxSource;
|
|
16
|
+
getPageSections?: typeof defaultGetPageSections;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata({
|
|
20
|
+
params,
|
|
21
|
+
}: Pick<Props, "params">): Promise<Metadata> {
|
|
22
|
+
const { locale } = await params;
|
|
23
|
+
return renderPageMetadata({ type: "PrivacyPage", slug: "privacy", locale });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function Page({
|
|
27
|
+
params,
|
|
28
|
+
getMdxSource,
|
|
29
|
+
getPageSections,
|
|
30
|
+
}: Props): Promise<ReactElement> {
|
|
31
|
+
const { locale } = await params;
|
|
32
|
+
return renderPage({
|
|
33
|
+
type: "PrivacyPage",
|
|
34
|
+
slug: "privacy",
|
|
35
|
+
locale,
|
|
36
|
+
translationsNamespace: "privacy",
|
|
37
|
+
...(getMdxSource !== undefined && { getMdxSource }),
|
|
38
|
+
...(getPageSections !== undefined && { getPageSections }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Terms page. Reads the TermsPage MDX frontmatter, renders sections via
|
|
2
|
+
// SectionRenderer, and emits a JSON-LD <script>.
|
|
3
|
+
import type {
|
|
4
|
+
getMdxSource as defaultGetMdxSource,
|
|
5
|
+
getPageSections as defaultGetPageSections} from "@working-theory/page-renderer";
|
|
6
|
+
import {
|
|
7
|
+
renderPage,
|
|
8
|
+
renderPageMetadata
|
|
9
|
+
} from "@working-theory/page-renderer";
|
|
10
|
+
import type { Metadata } from "next";
|
|
11
|
+
import type { ReactElement } from "react";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
params: Promise<{ locale: string }>;
|
|
15
|
+
getMdxSource?: typeof defaultGetMdxSource;
|
|
16
|
+
getPageSections?: typeof defaultGetPageSections;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata({
|
|
20
|
+
params,
|
|
21
|
+
}: Pick<Props, "params">): Promise<Metadata> {
|
|
22
|
+
const { locale } = await params;
|
|
23
|
+
return renderPageMetadata({ type: "TermsPage", slug: "terms", locale });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default async function Page({
|
|
27
|
+
params,
|
|
28
|
+
getMdxSource,
|
|
29
|
+
getPageSections,
|
|
30
|
+
}: Props): Promise<ReactElement> {
|
|
31
|
+
const { locale } = await params;
|
|
32
|
+
return renderPage({
|
|
33
|
+
type: "TermsPage",
|
|
34
|
+
slug: "terms",
|
|
35
|
+
locale,
|
|
36
|
+
translationsNamespace: "terms",
|
|
37
|
+
...(getMdxSource !== undefined && { getMdxSource }),
|
|
38
|
+
...(getPageSections !== undefined && { getPageSections }),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
* Returns a plain-text index of AILK's content surface for LLM consumption,
|
|
5
5
|
* following the llms.txt convention (https://llmstxt.org).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Indexes the section catalog (MDX seeds in content/) via
|
|
8
|
+
* @working-theory/content-adapters. Nothing is gated: a Free site has no blog
|
|
9
|
+
* (D-46), so there is no blog corpus to omit — `getBlogPages` defaults to an
|
|
10
|
+
* empty list and the docs + blog module ships its own variant of this route
|
|
11
|
+
* that reads `blogSource` (#5365 D9).
|
|
10
12
|
*
|
|
11
13
|
* Format per entry:
|
|
12
14
|
* - Title: <title>
|
|
@@ -14,8 +16,9 @@
|
|
|
14
16
|
* Description: <description>
|
|
15
17
|
*
|
|
16
18
|
* DI note: `createLlmsHandler` accepts optional `getContentAdapter` and
|
|
17
|
-
* `getBlogPages` deps
|
|
18
|
-
*
|
|
19
|
+
* `getBlogPages` deps — tests inject stubs, and the module's variant of this
|
|
20
|
+
* route supplies the real `blogSource` reader. The exported `GET` is
|
|
21
|
+
* unchanged either way.
|
|
19
22
|
*/
|
|
20
23
|
|
|
21
24
|
import { SCHEMA_ORG_TYPES } from "@working-theory/content-adapters";
|
|
@@ -23,7 +26,6 @@ import type { ContentAdapter, SchemaOrgType } from "@working-theory/content-adap
|
|
|
23
26
|
import { getContentAdapter as defaultGetContentAdapter } from "@working-theory/page-renderer";
|
|
24
27
|
|
|
25
28
|
import { SITE_NAME } from "../../lib/site-brand";
|
|
26
|
-
import { blogSource as defaultBlogSource } from "../../lib/source";
|
|
27
29
|
import { resolveBaseUrl, slugToPath } from "../../src/lib/routes";
|
|
28
30
|
|
|
29
31
|
export interface LlmsHandlerDeps {
|
|
@@ -33,8 +35,9 @@ export interface LlmsHandlerDeps {
|
|
|
33
35
|
*/
|
|
34
36
|
getContentAdapter?: () => ContentAdapter;
|
|
35
37
|
/**
|
|
36
|
-
* Blog pages getter. Defaults to
|
|
37
|
-
*
|
|
38
|
+
* Blog pages getter. Defaults to none — Free has no blog (D-46, #5365 D9).
|
|
39
|
+
* The docs + blog module's own copy of this route reads `blogSource`.
|
|
40
|
+
* Override in tests to inject stub pages.
|
|
38
41
|
*/
|
|
39
42
|
getBlogPages?: () => Array<{ url: string; data: { title: string; description?: string } }>;
|
|
40
43
|
}
|
|
@@ -45,7 +48,7 @@ export interface LlmsHandlerDeps {
|
|
|
45
48
|
*/
|
|
46
49
|
export function createLlmsHandler(deps: LlmsHandlerDeps = {}) {
|
|
47
50
|
const resolveAdapter = deps.getContentAdapter ?? defaultGetContentAdapter;
|
|
48
|
-
const resolveBlogPages = deps.getBlogPages ?? (() =>
|
|
51
|
+
const resolveBlogPages = deps.getBlogPages ?? (() => []);
|
|
49
52
|
|
|
50
53
|
return async function llmsGET(): Promise<Response> {
|
|
51
54
|
const adapter = resolveAdapter();
|
|
@@ -11,11 +11,11 @@ module.exports = {
|
|
|
11
11
|
],
|
|
12
12
|
testMatch: ["**/__tests__/**/*.test.ts", "**/__tests__/**/*.test.tsx"],
|
|
13
13
|
testPathIgnorePatterns: ["/node_modules/", "/.next/", "/dist/"],
|
|
14
|
-
// Ignore node_modules except
|
|
14
|
+
// Ignore node_modules except @working-theory/* (their dist is ESM).
|
|
15
15
|
// Mirrors the canonical jose carve-out used in apps/api, apps/mcp, and apps-paid/license-issuer.
|
|
16
16
|
// Added: issue #1077
|
|
17
17
|
transformIgnorePatterns: [
|
|
18
|
-
"/node_modules/(?!(\\.pnpm/)
|
|
18
|
+
"/node_modules/(?!(\\.pnpm/)?@working-theory(?:\\+[^/]*?@?[^/]*?|/[^/]+)(/|$))",
|
|
19
19
|
],
|
|
20
20
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"],
|
|
21
21
|
// Workspace packages publish ESM in dist/, but ts-jest runs in CommonJS.
|
|
@@ -27,12 +27,6 @@ module.exports = {
|
|
|
27
27
|
// Map all *.css to an empty stub — layout.tsx imports ./globals.css (#4090 item 1)
|
|
28
28
|
// and CSS is not parseable by ts-jest's CommonJS transform (apps-paid/marketing-web precedent, #1531).
|
|
29
29
|
"\\.css$": "<rootDir>/__tests__/__mocks__/style-mock.js",
|
|
30
|
-
// Fumadocs codegen output — produced by `pnpm --filter @working-theory/web build` into .source/
|
|
31
|
-
// The server entry uses top-level await + ESM-only fumadocs-mdx/runtime/server;
|
|
32
|
-
// map to a CJS stub so ts-jest can load modules that import lib/source.ts. (#1077)
|
|
33
|
-
// Stub lives in lib/__mocks__/ (committed) not .source/__mocks__/ (gitignored).
|
|
34
|
-
"^@/\\.source/server$": "<rootDir>/lib/__mocks__/source-server.js",
|
|
35
|
-
"^@/\\.source$": "<rootDir>/.source/index.ts",
|
|
36
30
|
"^@working-theory/page-renderer/testing$":
|
|
37
31
|
"<rootDir>/node_modules/@working-theory/page-renderer/dist/testing.js",
|
|
38
32
|
"^@working-theory/page-renderer$":
|
|
@@ -51,8 +45,6 @@ module.exports = {
|
|
|
51
45
|
"^@working-theory/api-client$": "<rootDir>/node_modules/@working-theory/api-client/dist/index.js",
|
|
52
46
|
"^@working-theory/content-adapters$":
|
|
53
47
|
"<rootDir>/node_modules/@working-theory/content-adapters/dist/index.js",
|
|
54
|
-
"^@working-theory/fumadocs-schema$":
|
|
55
|
-
"<rootDir>/node_modules/@working-theory/fumadocs-schema/dist/index.js",
|
|
56
48
|
"^@working-theory/license$": "<rootDir>/node_modules/@working-theory/license/dist/index.js",
|
|
57
49
|
"^@working-theory/jsonld$": "<rootDir>/node_modules/@working-theory/jsonld/dist/index.js",
|
|
58
50
|
"^@working-theory/metadata$": "<rootDir>/node_modules/@working-theory/metadata/dist/index.js",
|
|
@@ -66,6 +58,7 @@ module.exports = {
|
|
|
66
58
|
"<rootDir>/node_modules/@working-theory/schema-validator/dist/index.js",
|
|
67
59
|
"^@working-theory/sections-registry$":
|
|
68
60
|
"<rootDir>/node_modules/@working-theory/sections-registry/dist/index.js",
|
|
61
|
+
|
|
69
62
|
"^@working-theory/templates/shells$":
|
|
70
63
|
"<rootDir>/node_modules/@working-theory/templates/dist/shells/index.js",
|
|
71
64
|
"^@working-theory/templates$": "<rootDir>/node_modules/@working-theory/templates/dist/index.js",
|
|
@@ -82,6 +75,14 @@ module.exports = {
|
|
|
82
75
|
// tree, where nothing imports it, so the unused mapping is inert there.
|
|
83
76
|
"^@working-theory/ui/slices/scheduling$":
|
|
84
77
|
"<rootDir>/node_modules/@working-theory/ui/dist/sections/slices/scheduling.js",
|
|
78
|
+
// #5366: the signal-collectors slice's re-export subpath. Same reasoning
|
|
79
|
+
// as the scheduling mapping above.
|
|
80
|
+
"^@working-theory/ui/slices/signal-collectors$":
|
|
81
|
+
"<rootDir>/node_modules/@working-theory/ui/dist/sections/slices/signal-collectors.js",
|
|
82
|
+
// #5364: the commerce slice's renderer-registration + CheckoutPriceCard
|
|
83
|
+
// re-export subpath. Same reasoning as the scheduling mapping above.
|
|
84
|
+
"^@working-theory/ui/slices/commerce$":
|
|
85
|
+
"<rootDir>/node_modules/@working-theory/ui/dist/sections/slices/commerce.js",
|
|
85
86
|
"^@working-theory/theme$": "<rootDir>/node_modules/@working-theory/theme/dist/index.js",
|
|
86
87
|
// site-config publishes ESM in dist/; map to source so ts-jest compiles it
|
|
87
88
|
// through the same transformer as every sibling above. Only the
|
|
@@ -91,6 +92,11 @@ module.exports = {
|
|
|
91
92
|
"<rootDir>/node_modules/@working-theory/site-config/dist/schema/index.js",
|
|
92
93
|
"^@working-theory/validation$": "<rootDir>/node_modules/@working-theory/validation/dist/index.js",
|
|
93
94
|
"^@working-theory/web-i18n$": "<rootDir>/node_modules/@working-theory/web-i18n/dist/index.js",
|
|
95
|
+
// The dependency-free tenancy-constants subpath (database/tenancy.ts —
|
|
96
|
+
// it imports only a type from @working-theory/ids). Mapped to source like
|
|
97
|
+
// every sibling above; `database/dist` is not built in this workspace
|
|
98
|
+
// pre-`pnpm build`.
|
|
99
|
+
"^@working-theory/database/tenancy$": "<rootDir>/node_modules/@working-theory/database/dist/tenancy.js",
|
|
94
100
|
// #5025: pnpm keys next-intl's virtual-store path on its resolved peers,
|
|
95
101
|
// so apps/web and packages/page-renderer can link two PHYSICALLY DISTINCT
|
|
96
102
|
// copies of the same version — and a `jest.mock("next-intl/server")` in
|
|
@@ -126,9 +132,9 @@ module.exports = {
|
|
|
126
132
|
},
|
|
127
133
|
setupFilesAfterEnv: ["<rootDir>/__tests__/setup.ts"],
|
|
128
134
|
transform: {
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
135
|
+
// Some `@working-theory/*` dist JS ships `import.meta`, which the
|
|
136
|
+
// transformIgnorePatterns carve-out above lets reach a transformer
|
|
137
|
+
// instead of being required raw.
|
|
132
138
|
// `import.meta` has no CJS form, so it must run through the shared
|
|
133
139
|
// import.meta -> {} rewrite BEFORE ts-jest — ts-jest's own
|
|
134
140
|
// astTransformers hook never fires for a node_modules JS file (see the
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `forwardedCookieInit` — the RSC cookie/origin-forwarding helper
|
|
3
|
+
* (#5371 shepherd fix-up).
|
|
4
|
+
*
|
|
5
|
+
* Contract: the returned `init.headers` always carries the forwarded
|
|
6
|
+
* `cookie`, and carries `origin` ONLY when the incoming request's `Origin`
|
|
7
|
+
* header is present — never a fabricated value. This is what lets a Server
|
|
8
|
+
* Action `PUT`/`PATCH` through `@working-theory/api-client`'s `workspace.*`
|
|
9
|
+
* namespace pass `apps/api`'s same-origin CSRF check (`isOriginAllowed`),
|
|
10
|
+
* which Node's server-side `fetch` cannot satisfy on its own since it never
|
|
11
|
+
* sets `Origin`.
|
|
12
|
+
*/
|
|
13
|
+
import { forwardedCookieInit } from "../server-api";
|
|
14
|
+
|
|
15
|
+
const mockCookies = jest.fn();
|
|
16
|
+
const mockHeaders = jest.fn();
|
|
17
|
+
|
|
18
|
+
jest.mock("next/headers", () => ({
|
|
19
|
+
__esModule: true,
|
|
20
|
+
cookies: (...args: unknown[]) => mockCookies(...args),
|
|
21
|
+
headers: (...args: unknown[]) => mockHeaders(...args),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
describe("forwardedCookieInit", () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
mockCookies.mockReset();
|
|
27
|
+
mockHeaders.mockReset();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("forwards cookie + origin when the incoming request carries an Origin header", async () => {
|
|
31
|
+
mockCookies.mockResolvedValue({
|
|
32
|
+
toString: () => "better-auth.session_token=abc",
|
|
33
|
+
});
|
|
34
|
+
mockHeaders.mockResolvedValue(
|
|
35
|
+
new Headers({ origin: "https://app.example.com" }),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const init = await forwardedCookieInit();
|
|
39
|
+
|
|
40
|
+
expect(init).toEqual({
|
|
41
|
+
headers: {
|
|
42
|
+
cookie: "better-auth.session_token=abc",
|
|
43
|
+
origin: "https://app.example.com",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("forwards cookie alone — no origin key at all — when Origin is absent", async () => {
|
|
49
|
+
mockCookies.mockResolvedValue({
|
|
50
|
+
toString: () => "better-auth.session_token=abc",
|
|
51
|
+
});
|
|
52
|
+
mockHeaders.mockResolvedValue(new Headers());
|
|
53
|
+
|
|
54
|
+
const init = await forwardedCookieInit();
|
|
55
|
+
|
|
56
|
+
expect(init).toEqual({
|
|
57
|
+
headers: { cookie: "better-auth.session_token=abc" },
|
|
58
|
+
});
|
|
59
|
+
expect(init.headers).not.toHaveProperty("origin");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -3,22 +3,26 @@
|
|
|
3
3
|
* (#4665 D9).
|
|
4
4
|
*
|
|
5
5
|
* Forwards the incoming request's cookies to `@working-theory/api-client`'s
|
|
6
|
-
* `waitlistExperiments`
|
|
7
|
-
* auth preHandler resolves the SAME Better Auth
|
|
8
|
-
* both apps share the session store.
|
|
9
|
-
* is
|
|
6
|
+
* `waitlistExperiments` / `workspace` namespaces (B0, #4671; #5371) so
|
|
7
|
+
* `apps/api`'s cookie-session auth preHandler resolves the SAME Better Auth
|
|
8
|
+
* session the browser holds — both apps share the session store. Every page
|
|
9
|
+
* is an RSC and every write is a Server Action; there is no client fetch and
|
|
10
|
+
* no `NEXT_PUBLIC_` credential (D9). For a Server Action `PUT`/`PATCH`, the
|
|
11
|
+
* incoming request's `Origin` is forwarded alongside the cookie so
|
|
12
|
+
* `apps/api`'s same-origin CSRF check (`isOriginAllowed`) passes — Node's
|
|
13
|
+
* server-side `fetch` never sets `Origin` on its own.
|
|
10
14
|
*
|
|
11
15
|
* `apps/web` may not import `apps/api` directly (architecture.yaml) — every
|
|
12
|
-
*
|
|
16
|
+
* call goes through `@working-theory/api-client`'s typed namespace, never a
|
|
13
17
|
* hand-rolled `fetch`. This module supplies exactly the two things that
|
|
14
|
-
* namespace doesn't own: the cookie-forwarding `init` (B0's additive
|
|
18
|
+
* namespace doesn't own: the cookie/origin-forwarding `init` (B0's additive
|
|
15
19
|
* `init?: { headers }` on `http.get`) and the envelope→`ApiError` unwrap
|
|
16
20
|
* (mirrors `apps-paid/workspace/lib/api-error.ts`'s `unwrapEnvelope`, adapted to
|
|
17
21
|
* the `@working-theory/api-client` `ApiResult<T>` shape B0 already returns
|
|
18
22
|
* rather than re-parsing the wire envelope by hand).
|
|
19
23
|
*/
|
|
20
24
|
|
|
21
|
-
import { cookies } from "next/headers";
|
|
25
|
+
import { cookies, headers } from "next/headers";
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Structural mirror of `@working-theory/api-client`'s `ApiResult<T>`
|
|
@@ -57,15 +61,27 @@ interface ErrorBody {
|
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
/**
|
|
60
|
-
* Forward the incoming request's cookies
|
|
61
|
-
* `waitlistExperiments.*` call accepts.
|
|
62
|
-
*
|
|
64
|
+
* Forward the incoming request's cookies — and, when present, its `Origin` —
|
|
65
|
+
* as the `init` every `waitlistExperiments.*` / `workspace.*` call accepts.
|
|
66
|
+
* Call once per request — `cookies()` / `headers()` read the current RSC
|
|
67
|
+
* request context.
|
|
68
|
+
*
|
|
69
|
+
* The `Origin` forward matters for every non-GET call: `apps/api`'s
|
|
70
|
+
* `authPreHandler` (`isOriginAllowed`) requires a matching `Origin` header on
|
|
71
|
+
* a cookie-authenticated mutating request, and Node's server-side `fetch`
|
|
72
|
+
* (unlike a browser XHR/fetch) never sets one on its own. A Server Action's
|
|
73
|
+
* incoming request DOES carry the browser's real `Origin`, so re-forwarding
|
|
74
|
+
* it here — rather than fabricating one — lets a genuine same-origin write
|
|
75
|
+
* pass the check exactly as a browser-originated one would. RSC `GET`s are
|
|
76
|
+
* unaffected: `isOriginAllowed` short-circuits `true` for safe methods before
|
|
77
|
+
* it ever inspects the header.
|
|
63
78
|
*/
|
|
64
79
|
export async function forwardedCookieInit(): Promise<{
|
|
65
|
-
headers: { cookie: string };
|
|
80
|
+
headers: { cookie: string; origin?: string };
|
|
66
81
|
}> {
|
|
67
82
|
const cookieHeader = (await cookies()).toString();
|
|
68
|
-
|
|
83
|
+
const origin = (await headers()).get("origin");
|
|
84
|
+
return { headers: { cookie: cookieHeader, ...(origin ? { origin } : {}) } };
|
|
69
85
|
}
|
|
70
86
|
|
|
71
87
|
/**
|
|
@@ -171,6 +171,14 @@
|
|
|
171
171
|
"heading": "Partners",
|
|
172
172
|
"emptyState": "Partners listing coming soon."
|
|
173
173
|
},
|
|
174
|
+
"pricing": {
|
|
175
|
+
"heading": "Pricing",
|
|
176
|
+
"emptyState": "Pricing page content coming soon."
|
|
177
|
+
},
|
|
178
|
+
"privacy": {
|
|
179
|
+
"heading": "Privacy Policy",
|
|
180
|
+
"emptyState": "Privacy policy content coming soon."
|
|
181
|
+
},
|
|
174
182
|
"products": {
|
|
175
183
|
"heading": "Products",
|
|
176
184
|
"emptyState": "Products listing coming soon."
|
|
@@ -215,6 +223,10 @@
|
|
|
215
223
|
"description": "Deep dives into the architecture and internals of this site.",
|
|
216
224
|
"emptyState": "Technical articles coming soon."
|
|
217
225
|
},
|
|
226
|
+
"terms": {
|
|
227
|
+
"heading": "Terms of Service",
|
|
228
|
+
"emptyState": "Terms of service content coming soon."
|
|
229
|
+
},
|
|
218
230
|
"testimonials": {
|
|
219
231
|
"heading": "Testimonials",
|
|
220
232
|
"emptyState": "Testimonials coming soon."
|
|
@@ -395,5 +407,51 @@
|
|
|
395
407
|
"emptyHeadline": "No purchases yet",
|
|
396
408
|
"emptyDescription": "Purchases you complete will appear here."
|
|
397
409
|
}
|
|
410
|
+
},
|
|
411
|
+
"workspace": {
|
|
412
|
+
"title": "Workspace settings",
|
|
413
|
+
"description": "Your workspace name, site settings, and team.",
|
|
414
|
+
"nav": {
|
|
415
|
+
"account": "Account",
|
|
416
|
+
"general": "General",
|
|
417
|
+
"site": "Site",
|
|
418
|
+
"team": "Team"
|
|
419
|
+
},
|
|
420
|
+
"general": {
|
|
421
|
+
"heading": "General",
|
|
422
|
+
"nameLabel": "Workspace name",
|
|
423
|
+
"saveButton": "Save",
|
|
424
|
+
"saving": "Saving\u2026",
|
|
425
|
+
"saved": "Saved",
|
|
426
|
+
"saveError": "Could not save. Try again."
|
|
427
|
+
},
|
|
428
|
+
"site": {
|
|
429
|
+
"heading": "Site",
|
|
430
|
+
"identityHeading": "Identity",
|
|
431
|
+
"identityName": "Site name",
|
|
432
|
+
"identityUrl": "Site URL",
|
|
433
|
+
"identityDescription": "Description",
|
|
434
|
+
"seoHeading": "SEO",
|
|
435
|
+
"seoDescription": "Meta description",
|
|
436
|
+
"seoOgImage": "Social share image URL",
|
|
437
|
+
"themeHeading": "Theme",
|
|
438
|
+
"themeLightPrimary": "Primary colour (light)",
|
|
439
|
+
"themeLightAccent": "Accent colour (light)",
|
|
440
|
+
"themeDarkPrimary": "Primary colour (dark)",
|
|
441
|
+
"themeDarkAccent": "Accent colour (dark)",
|
|
442
|
+
"themeUnconfigured": "This site uses the default theme. Colours become editable once a theme is configured for the workspace.",
|
|
443
|
+
"saveButton": "Save",
|
|
444
|
+
"saving": "Saving\u2026",
|
|
445
|
+
"saved": "Saved",
|
|
446
|
+
"saveError": "Could not save. Try again."
|
|
447
|
+
},
|
|
448
|
+
"team": {
|
|
449
|
+
"heading": "Team",
|
|
450
|
+
"name": "Name",
|
|
451
|
+
"email": "Email",
|
|
452
|
+
"role": "Role",
|
|
453
|
+
"emptyHeadline": "No members yet",
|
|
454
|
+
"emptyDescription": "People with access to this workspace will appear here."
|
|
455
|
+
}
|
|
398
456
|
}
|
|
399
457
|
}
|