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
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
* `architecture.yaml` template files — a fixed template IS the drift this
|
|
22
22
|
* removes.
|
|
23
23
|
*/
|
|
24
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
25
|
+
import { dirname, join, sep } from "node:path";
|
|
26
|
+
import { PAID_MODULES } from "./lib/module-tier.js";
|
|
24
27
|
import { RECOGNIZED_MODULES } from "./parse-args.js";
|
|
25
28
|
/**
|
|
26
29
|
* The standalone-site "no upstream-monorepo import" forbidden pattern, assembled
|
|
@@ -65,6 +68,19 @@ const PUBLIC_SCHEDULING_VAR_PATTERN = [
|
|
|
65
68
|
"CAL",
|
|
66
69
|
"_|CALCOM|CALENDAR|SCHEDUL|BOOKING)",
|
|
67
70
|
].join("");
|
|
71
|
+
/**
|
|
72
|
+
* The commerce module's one credential-boundary pattern: a live-mode Stripe
|
|
73
|
+
* key shape (`sk_`/`pk_`/`rk_` + the live-mode infix), assembled from
|
|
74
|
+
* fragments for the same reason as CAL_KEY_PATTERN above — a literal
|
|
75
|
+
* live-key-shaped token in this file's source would itself trip the repo's
|
|
76
|
+
* own live-key hard block (`rules/environment-boundaries.md`). `apps/api` is
|
|
77
|
+
* excluded because `STRIPE_SECRET_KEY` legitimately lives there, gated by
|
|
78
|
+
* `assertSandboxKey`'s sandbox-only allow-list at request time and by
|
|
79
|
+
* `assertCommerceSandboxKey` at boot (server.ts) — this pattern catches a
|
|
80
|
+
* live-shaped key leaking anywhere ELSE (a fixture, a client component, a
|
|
81
|
+
* `NEXT_PUBLIC_` var).
|
|
82
|
+
*/
|
|
83
|
+
const STRIPE_LIVE_KEY_PATTERN = ["(sk|pk|rk)_li", "ve_[A-Za-z0-9]"].join("");
|
|
68
84
|
/**
|
|
69
85
|
* The module-independent base: `apps/web` (the Next.js presentation shell every
|
|
70
86
|
* AILK site has) plus the standalone forbidden-pattern floor. `may_import_from`
|
|
@@ -193,8 +209,8 @@ export const MODULE_SLICES = {
|
|
|
193
209
|
},
|
|
194
210
|
},
|
|
195
211
|
},
|
|
196
|
-
// ── docs —
|
|
197
|
-
docs: {
|
|
212
|
+
// ── docs-blog — Pro module: both fumadocs surfaces (D-46) ────────────────
|
|
213
|
+
"docs-blog": {
|
|
198
214
|
webImports: ["packages/fumadocs-schema"],
|
|
199
215
|
packages: {
|
|
200
216
|
"fumadocs-schema": {
|
|
@@ -202,27 +218,179 @@ export const MODULE_SLICES = {
|
|
|
202
218
|
may_import_from: ["packages/schema", "packages/validation"],
|
|
203
219
|
},
|
|
204
220
|
},
|
|
205
|
-
// ownedFiles (S1, #5088).
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
221
|
+
// ownedFiles (S1, #5088; widened by #5365). The standing reason to list
|
|
222
|
+
// only the `/docs` route was that `/blog` was a FREE route, which made
|
|
223
|
+
// `lib/source.ts` and `source.config.ts` genuinely mixed files a strip
|
|
224
|
+
// tool could not touch without breaking every OSS build. D-46 removed
|
|
225
|
+
// that premise: docs and blog are ONE Pro module and Free has no blog, so
|
|
226
|
+
// both files are wholly module-owned and move whole (#5365 D3). Nothing
|
|
227
|
+
// in a Free `apps/web` resolves a Fumadocs collection afterwards, which is
|
|
228
|
+
// also why `apps/web/content/<locale>/{blog,docs}` no longer has to exist
|
|
229
|
+
// in every scaffold — see `programmatic.ts`'s note and #5365 D3.
|
|
230
|
+
//
|
|
231
|
+
// `packages/fumadocs-schema/**` is still deliberately NOT listed. It is a
|
|
232
|
+
// permission, not a physical slice: `webImports` above names it so a
|
|
233
|
+
// scaffold that installs this module declares the import, while the
|
|
234
|
+
// package itself stays in the tree for this repo's own marketing site. Its
|
|
235
|
+
// tier, licence and npm access flip together under #5363 (D-43) — after
|
|
236
|
+
// this extraction, because architecture.yaml's recorded reason for the
|
|
237
|
+
// current `oss` tier is the Free `/blog` route this card just retired.
|
|
238
|
+
//
|
|
239
|
+
// SOURCE files only (the rule above): the three `content/en/**` MDX files
|
|
240
|
+
// and every test/story companion carry the `oss: false` marker but are not
|
|
241
|
+
// listed here.
|
|
242
|
+
ownedFiles: [
|
|
243
|
+
// The two route surfaces the module mounts.
|
|
244
|
+
"apps/web/app/[locale]/blog/[[...slug]]/page.tsx",
|
|
245
|
+
"apps/web/app/[locale]/docs/[[...slug]]/page.tsx",
|
|
246
|
+
// The Fumadocs source pair — both whole, both loaders (D3).
|
|
247
|
+
"apps/web/source.config.ts",
|
|
248
|
+
"apps/web/lib/source.ts",
|
|
249
|
+
// The route adapters and the jest stub for the codegen output.
|
|
250
|
+
"apps/web/lib/blog-list-data.ts",
|
|
251
|
+
"apps/web/lib/blog-post-data.ts",
|
|
252
|
+
"apps/web/lib/__mocks__/source-server.js",
|
|
253
|
+
// The module's own /llms.txt variant; the bundle installs it onto
|
|
254
|
+
// app/llms.txt/route.ts (#5365 D9, install-path mapping owned by #5373).
|
|
255
|
+
"apps/web/lib/slices/docs-blog/llms-route.ts",
|
|
256
|
+
// The two shells and the six components, each off its public barrel and
|
|
257
|
+
// reachable only from the slice barrel that leaves with them (D-45, D5).
|
|
258
|
+
"packages/templates/src/shells/BlogShell.tsx",
|
|
259
|
+
"packages/templates/src/shells/DocsShell.tsx",
|
|
260
|
+
"packages/templates/src/shells/slices/docs-blog.ts",
|
|
261
|
+
"packages/ui/src/blocks/DocsActionBar.tsx",
|
|
262
|
+
"packages/ui/src/blocks/DocsArticleHeader.tsx",
|
|
263
|
+
"packages/ui/src/blocks/DocsFeedback.tsx",
|
|
264
|
+
"packages/ui/src/blocks/DocsSearch.tsx",
|
|
265
|
+
"packages/ui/src/blocks/DocsTocButton.tsx",
|
|
266
|
+
"packages/ui/src/chrome/DocsSidebar.tsx",
|
|
267
|
+
"packages/ui/src/chrome/slices/docs-blog.ts",
|
|
268
|
+
],
|
|
269
|
+
// pageContributions (spec 5478; parent § D6 shape 1) — the two route
|
|
270
|
+
// surfaces this module mounts, each with the seed MDX it renders. The
|
|
271
|
+
// three MDX files are exactly the three on the tree and cannot come from
|
|
272
|
+
// the `templates/` snapshot: `apps/web/content` is in build-templates.mjs's
|
|
273
|
+
// EXCLUDE_TEMPLATE_DIRS and `template-overlay/` carries no blog or docs
|
|
274
|
+
// stub. They ride this module's own bundle, consistent with the route
|
|
275
|
+
// files above — STAGING them into it is #5481's change to
|
|
276
|
+
// build-module-bundles.mjs, since `collectModuleFiles` unions `ownedFiles`
|
|
277
|
+
// with `installMap` keys and nothing else. This unit only DECLARES them.
|
|
278
|
+
pageContributions: [
|
|
279
|
+
{
|
|
280
|
+
route: "/blog",
|
|
281
|
+
content: [
|
|
282
|
+
"apps/web/content/en/blog/index.mdx",
|
|
283
|
+
"apps/web/content/en/blog/launching-ailk.mdx",
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
route: "/docs",
|
|
288
|
+
content: ["apps/web/content/en/docs/getting-started.mdx"],
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
// patches (spec 5418 § 3 D1, Group G) — every Group G row that edits a
|
|
292
|
+
// file the buyer's scaffold already has. Values transcribed verbatim
|
|
293
|
+
// from docs/specs/5365-docs-blog-module-spec.md § 4 Group G via
|
|
294
|
+
// docs/specs/5418-module-bundle-patch-set-spec.md § 3 D1's table; the
|
|
295
|
+
// fumadocs-core/fumadocs-mdx version strings are read from this repo's
|
|
296
|
+
// own apps/web/package.json at HEAD.
|
|
211
297
|
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
// (
|
|
225
|
-
|
|
298
|
+
// Group G's tsconfig.json row (D1 row 8 — restoring the
|
|
299
|
+
// `../../packages/fumadocs-schema` project reference) is deliberately
|
|
300
|
+
// NOT included here. Re-anchoring D1 against a real keyless scaffold
|
|
301
|
+
// (5418 build, Deliverable 0) found `apps/web/tsconfig.json` carries no
|
|
302
|
+
// `references` key at all in ANY scaffold, regardless of `--modules`
|
|
303
|
+
// selection: `build-templates.mjs`'s `stripDanglingProjectReferences()`
|
|
304
|
+
// runs once over the fixed templates/ snapshot, which never contains a
|
|
305
|
+
// `packages/` directory, so every one of the monorepo's 15 references
|
|
306
|
+
// (including `fumadocs-schema`, position 6) resolves to a nonexistent
|
|
307
|
+
// path and the whole property is dropped. `@working-theory/fumadocs-schema`
|
|
308
|
+
// is delivered to a scaffold as an npm/bundle dependency under
|
|
309
|
+
// `node_modules/`, never as a `packages/fumadocs-schema` source sibling
|
|
310
|
+
// (see this slice's own `ownedFiles` comment above), so restoring the
|
|
311
|
+
// reference would immediately be dangling again in every scaffold — the
|
|
312
|
+
// exact condition `stripDanglingProjectReferences()` exists to prevent,
|
|
313
|
+
// which breaks `next build`'s TypeScript pass (#4090 item 2). This is
|
|
314
|
+
// the same reasoning the commerce row (5418 D1 row 9) already applies to
|
|
315
|
+
// its own tsconfig.json omission; applied here for consistency.
|
|
316
|
+
//
|
|
317
|
+
// Group G's fourth jest.config.cjs item (the `import.meta` transform
|
|
318
|
+
// entry) needs no patch either — the scaffold already ships it
|
|
319
|
+
// untouched (5418 D1 row 7b) — so `add-transform` has no concrete use
|
|
320
|
+
// here.
|
|
321
|
+
patches: [
|
|
322
|
+
{
|
|
323
|
+
target: "apps/web/package.json",
|
|
324
|
+
kind: "json",
|
|
325
|
+
ops: [
|
|
326
|
+
{
|
|
327
|
+
op: "merge-keys",
|
|
328
|
+
path: ["dependencies"],
|
|
329
|
+
entries: {
|
|
330
|
+
"fumadocs-core": "^16.10.4",
|
|
331
|
+
"fumadocs-mdx": "^15.0.12",
|
|
332
|
+
"@working-theory/fumadocs-schema": "workspace:*",
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
op: "merge-keys",
|
|
337
|
+
path: ["scripts"],
|
|
338
|
+
entries: {
|
|
339
|
+
prebuild: "fumadocs-mdx",
|
|
340
|
+
pretypecheck: "fumadocs-mdx",
|
|
341
|
+
pretest: "fumadocs-mdx",
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
target: "apps/web/next.config.mjs",
|
|
348
|
+
kind: "next-config",
|
|
349
|
+
ops: [
|
|
350
|
+
{
|
|
351
|
+
op: "add-transpile-package",
|
|
352
|
+
package: "@working-theory/fumadocs-schema",
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
op: "wrap-export-with",
|
|
356
|
+
importLine: 'import { createMDX } from "fumadocs-mdx/next";\n',
|
|
357
|
+
find: "withNextIntl(nextConfig)",
|
|
358
|
+
replaceWith: "withNextIntl(createMDX()(nextConfig))",
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
target: "apps/web/jest.config.cjs",
|
|
364
|
+
kind: "jest-config",
|
|
365
|
+
ops: [
|
|
366
|
+
{
|
|
367
|
+
op: "add-transform-ignore-pattern",
|
|
368
|
+
find: '"/node_modules/(?!(\\\\.pnpm/)?@working-theory(?:\\\\+[^/]*?@?[^/]*?|/[^/]+)(/|$))"',
|
|
369
|
+
replaceWith: '"/node_modules/(?!(\\\\.pnpm/)?(fumadocs-[^/]*?@?[^/]*?|@working-theory(?:\\\\+[^/]*?@?[^/]*?|/[^/]+))(/|$))"',
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
op: "add-module-name-mapper",
|
|
373
|
+
pattern: "^@/\\\\.source/server$",
|
|
374
|
+
value: "<rootDir>/lib/__mocks__/source-server.js",
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
op: "add-module-name-mapper",
|
|
378
|
+
pattern: "^@/\\\\.source$",
|
|
379
|
+
value: "<rootDir>/.source/index.ts",
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
op: "add-module-name-mapper",
|
|
383
|
+
pattern: "^@working-theory/fumadocs-schema$",
|
|
384
|
+
value: "<rootDir>/node_modules/@working-theory/fumadocs-schema/dist/index.js",
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
// postInstall shrinks to what patches cannot express (D5): the patch
|
|
390
|
+
// step edits package.json but never runs a package manager on the
|
|
391
|
+
// buyer's behalf, so a fresh pnpm-lock.yaml resolution is still the
|
|
392
|
+
// buyer's own next step.
|
|
393
|
+
postInstall: "run pnpm install",
|
|
226
394
|
},
|
|
227
395
|
// ── multi-tenant — full-stack module (data + api + presentation) ─────────
|
|
228
396
|
//
|
|
@@ -241,6 +409,12 @@ export const MODULE_SLICES = {
|
|
|
241
409
|
"packages/theme",
|
|
242
410
|
"packages/ui",
|
|
243
411
|
"packages/validation",
|
|
412
|
+
// The `workspace` module's shared settings components (#5371 req. 6)
|
|
413
|
+
// — the scaffolded-site twin of the root architecture.yaml grant on
|
|
414
|
+
// `apps_paid.workspace`. Pro Plus inherits Pro's module set, so a
|
|
415
|
+
// saas-product scaffold carries both modules and this app composes
|
|
416
|
+
// the identical panels apps/web does, with no forked copy.
|
|
417
|
+
"packages/workspace-ui",
|
|
244
418
|
],
|
|
245
419
|
may_not_import_from: [
|
|
246
420
|
"apps/api",
|
|
@@ -252,7 +426,7 @@ export const MODULE_SLICES = {
|
|
|
252
426
|
},
|
|
253
427
|
api: {
|
|
254
428
|
path: "apps/api",
|
|
255
|
-
description: "Public HTTP API — routes + services (Fastify). Owns webhooks,
|
|
429
|
+
description: "Public HTTP API — routes + services (Fastify). Owns webhooks, email, server-side analytics — checkout moved to the commerce module (D-47).",
|
|
256
430
|
may_import_from: [
|
|
257
431
|
"database",
|
|
258
432
|
"packages/analytics",
|
|
@@ -317,7 +491,7 @@ export const MODULE_SLICES = {
|
|
|
317
491
|
// Object.assign merge in deriveArchitecture is order-independent (a
|
|
318
492
|
// multi-tenant-only selection stays self-consistent).
|
|
319
493
|
templates: {
|
|
320
|
-
description: "Shell/Chrome composition — WorkspaceShell + ArtifactEditorShell (
|
|
494
|
+
description: "Shell/Chrome composition — AppShell (tier-5 shell); WorkspaceShell + ArtifactEditorShell ship inside this module itself, not the public package (D-45)",
|
|
321
495
|
may_import_from: ["packages/theme", "packages/ui", "packages/validation"],
|
|
322
496
|
},
|
|
323
497
|
theme: {
|
|
@@ -435,6 +609,24 @@ export const MODULE_SLICES = {
|
|
|
435
609
|
// not a documented module boundary — flagged for reviewer judgment
|
|
436
610
|
// rather than asserted here.
|
|
437
611
|
//
|
|
612
|
+
// apps/web/app/[locale]/(authed)/waitlist/** (#5367 FR4, D8): the operator
|
|
613
|
+
// waitlist-experiments dashboard UI. Reads GET /v1/waitlist-experiments,
|
|
614
|
+
// whose API half is already listed above. No prior module claimed
|
|
615
|
+
// apps/web at all for multi-tenant — #5182 §8 flagged this gap and left
|
|
616
|
+
// it for this card. Presentation follows its API (D-48: "Operator review
|
|
617
|
+
// dashboards stay in Pro Plus").
|
|
618
|
+
//
|
|
619
|
+
// ESCALATION (§5.3, posted to Epic #5378): the spec's §4.3 file list names
|
|
620
|
+
// 12 files including format.ts and components/ForbiddenState.tsx as
|
|
621
|
+
// multi-tenant-owned. Both are imported by the FREE
|
|
622
|
+
// apps/web/app/[locale]/(authed)/account/page.tsx (lines 55-56) — D-49
|
|
623
|
+
// keeps that page in Free. Listing them here would remove a Free
|
|
624
|
+
// consumer's dependency from the starter (§5.3's stop condition). Treated
|
|
625
|
+
// the same as this slice's own project-listings/index.ts + respond.ts
|
|
626
|
+
// precedent immediately above: a file shared between the free and paid
|
|
627
|
+
// surfaces stays OUT of ownedFiles. Only the other 10 of the 12 are
|
|
628
|
+
// listed below.
|
|
629
|
+
//
|
|
438
630
|
// database/auth/ and database/content/ — investigated, NOT listed.
|
|
439
631
|
// Both namespaces DO have their own schema.prisma file (a real
|
|
440
632
|
// filesystem split via Prisma's multi-file schema feature), but each
|
|
@@ -472,9 +664,103 @@ export const MODULE_SLICES = {
|
|
|
472
664
|
"apps/api/src/services/waitlist-dashboard.ts",
|
|
473
665
|
"apps/api/src/lib/tenant-db.ts",
|
|
474
666
|
"apps/api/src/lib/ws-token.ts",
|
|
667
|
+
"apps/web/app/[locale]/(authed)/waitlist/page.tsx",
|
|
668
|
+
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/page.tsx",
|
|
669
|
+
"apps/web/app/[locale]/(authed)/waitlist/[experimentId]/signups/[leadId]/page.tsx",
|
|
670
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/ExperimentsTable.tsx",
|
|
671
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/OfferFunnelTable.tsx",
|
|
672
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/RollupTicker.tsx",
|
|
673
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/ScoreTrace.tsx",
|
|
674
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/SignupsTable.tsx",
|
|
675
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/WaitlistComparisonTabs.tsx",
|
|
676
|
+
"apps/web/app/[locale]/(authed)/waitlist/components/status-badges.tsx",
|
|
475
677
|
"apps-paid/workspace/**",
|
|
476
678
|
],
|
|
477
679
|
},
|
|
680
|
+
// ── workspace — Pro module: the single-workspace settings shell (D-27/D-49)
|
|
681
|
+
//
|
|
682
|
+
// `/workspace` in apps/web's `(authed)` segment — General (rename), Site
|
|
683
|
+
// (identity / SEO / theme, over the already-shipped apps/api config routes)
|
|
684
|
+
// and Team (a read-only roster). The three panels live in the shared
|
|
685
|
+
// `packages/workspace-ui` package so the multi-tenant workspace app (the
|
|
686
|
+
// Pro Plus app) composes the identical components rather than a fork.
|
|
687
|
+
//
|
|
688
|
+
// No `apps` / `namespaces` / `forbiddenPatterns` block: this module
|
|
689
|
+
// contributes to already-declared apps only (apps/web is BASE; apps/api is
|
|
690
|
+
// declared by multi-tenant / scheduling / commerce and is snapshotted whole).
|
|
691
|
+
workspace: {
|
|
692
|
+
// A PERMISSION, not a physical slice (#5371 D1a) — the identical shape
|
|
693
|
+
// docs-blog uses for `packages/fumadocs-schema`. `packages/` is never in
|
|
694
|
+
// SNAPSHOT_DIRS, so the package reaches a buyer as an npm/bundle
|
|
695
|
+
// dependency under `node_modules/`, never as a `packages/workspace-ui`
|
|
696
|
+
// source sibling; the `patches` entry below is what puts it in the
|
|
697
|
+
// buyer's apps/web/package.json.
|
|
698
|
+
webImports: ["packages/workspace-ui"],
|
|
699
|
+
packages: {
|
|
700
|
+
"workspace-ui": {
|
|
701
|
+
description: "Shared workspace-settings components — the settings shell plus the General / Site / Team panels, presentational only (data + save callbacks as props)",
|
|
702
|
+
// packages/templates is required because WorkspaceSettingsShell
|
|
703
|
+
// composes AppShell from @working-theory/templates/shells — the same
|
|
704
|
+
// composition apps/web's own account page uses.
|
|
705
|
+
may_import_from: [
|
|
706
|
+
"packages/templates",
|
|
707
|
+
"packages/theme",
|
|
708
|
+
"packages/ui",
|
|
709
|
+
"packages/validation",
|
|
710
|
+
],
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
// SOURCE files only, and only the ones this module physically owns: the
|
|
714
|
+
// three apps/web route files and the two apps/api route files.
|
|
715
|
+
//
|
|
716
|
+
// `packages/workspace-ui/**` is deliberately NOT listed (D1a). It is a
|
|
717
|
+
// whole package that is paid end to end, whose strip disposition is
|
|
718
|
+
// carried by architecture.yaml's `commercial_tier_moves_to` field (its
|
|
719
|
+
// future paid-tree home) rather than by a per-file inventory —
|
|
720
|
+
// exactly the disposition `packages/fumadocs-schema` carries for
|
|
721
|
+
// docs-blog. `multi-tenant`'s whole-app glob (above) works because
|
|
722
|
+
// SNAPSHOT_DIRS physically copies apps wholesale; a package is never in a
|
|
723
|
+
// snapshot root, so an ownedFiles enumeration would add nothing.
|
|
724
|
+
//
|
|
725
|
+
// `packages/api-client/src/workspace.ts` is NOT listed either (D1b):
|
|
726
|
+
// api-client is a base package every scaffold receives regardless of
|
|
727
|
+
// `--modules`, and the field doc above names it by name as a shared
|
|
728
|
+
// package deliberately left out even when genuinely single-purpose. The
|
|
729
|
+
// wrapper is harmless on a scaffold without this module — its calls 404,
|
|
730
|
+
// the same non-event any client wrapper produces against an unregistered
|
|
731
|
+
// route.
|
|
732
|
+
//
|
|
733
|
+
// Test companions (`__tests__/`) are never listed — the SOURCE-files-only
|
|
734
|
+
// rule above.
|
|
735
|
+
ownedFiles: [
|
|
736
|
+
"apps/web/app/[locale]/(authed)/workspace/page.tsx",
|
|
737
|
+
"apps/web/app/[locale]/(authed)/workspace/site/page.tsx",
|
|
738
|
+
"apps/web/app/[locale]/(authed)/workspace/team/page.tsx",
|
|
739
|
+
"apps/api/src/routes/workspaces/general.ts",
|
|
740
|
+
"apps/api/src/routes/workspaces/members.ts",
|
|
741
|
+
],
|
|
742
|
+
// patches — the dependency add that delivers the shared package to the
|
|
743
|
+
// buyer's apps/web, mirroring docs-blog's own fumadocs-schema merge-keys
|
|
744
|
+
// op. No next.config.mjs `add-transpile-package` op: the package ships
|
|
745
|
+
// compiled ESM in dist/ the same way every other @working-theory/*
|
|
746
|
+
// dependency apps/web already consumes does, and docs-blog's transpile op
|
|
747
|
+
// exists for the fumadocs SDK boundary, not for the dependency add itself.
|
|
748
|
+
patches: [
|
|
749
|
+
{
|
|
750
|
+
target: "apps/web/package.json",
|
|
751
|
+
kind: "json",
|
|
752
|
+
ops: [
|
|
753
|
+
{
|
|
754
|
+
op: "merge-keys",
|
|
755
|
+
path: ["dependencies"],
|
|
756
|
+
entries: {
|
|
757
|
+
"@working-theory/workspace-ui": "workspace:*",
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
],
|
|
761
|
+
},
|
|
762
|
+
],
|
|
763
|
+
},
|
|
478
764
|
// ── scheduling — full-stack module (provider + routes + booker pages) ────
|
|
479
765
|
//
|
|
480
766
|
// The #4416 scheduling seam, made installable. Three tiers into the
|
|
@@ -511,7 +797,7 @@ export const MODULE_SLICES = {
|
|
|
511
797
|
apps: {
|
|
512
798
|
api: {
|
|
513
799
|
path: "apps/api",
|
|
514
|
-
description: "Public HTTP API — routes + services (Fastify). Owns webhooks,
|
|
800
|
+
description: "Public HTTP API — routes + services (Fastify). Owns webhooks, email, server-side analytics — checkout moved to the commerce module (D-47).",
|
|
515
801
|
may_import_from: [
|
|
516
802
|
"database",
|
|
517
803
|
"packages/analytics",
|
|
@@ -642,6 +928,377 @@ export const MODULE_SLICES = {
|
|
|
642
928
|
"apps/web/app/[locale]/schedule/page.tsx",
|
|
643
929
|
"apps/web/app/[locale]/schedule/confirmed/page.tsx",
|
|
644
930
|
],
|
|
931
|
+
// pageContributions (spec 5478; parent § D6 shape 1) — the booker and its
|
|
932
|
+
// confirmation page, whose route files `ownedFiles` above already carries.
|
|
933
|
+
// Neither row names seed content: both render from the /v1/schedule/*
|
|
934
|
+
// routes, not from an MDX file.
|
|
935
|
+
pageContributions: [
|
|
936
|
+
{ route: "/schedule" },
|
|
937
|
+
{ route: "/schedule/confirmed" },
|
|
938
|
+
],
|
|
939
|
+
},
|
|
940
|
+
// ── signal-collectors — flows, deliverables, project listings, waitlist
|
|
941
|
+
// signups (D-48, #5366) ───────────────────────────────────────────────
|
|
942
|
+
//
|
|
943
|
+
// ownedFiles verified against the current filesystem, server.ts's
|
|
944
|
+
// module-conditional registration (isModuleEnabled('signal-collectors')),
|
|
945
|
+
// and a repo-wide grep of every importer of each candidate file (an
|
|
946
|
+
// independent re-grep, not carried over from the spec's own table).
|
|
947
|
+
//
|
|
948
|
+
// apps/api/src/routes/project-listings/index.ts is MIXED (D4): it holds
|
|
949
|
+
// this module's five anonymous/founder-read re-exports (lines 1-55) AND
|
|
950
|
+
// multi-tenant's TENANT_HANDLERS table + projectListingTenantRoutes
|
|
951
|
+
// (lines 57-139) in one file. NOT listed here — never deleted/edited on
|
|
952
|
+
// its own, exactly like the scheduling/multi-tenant precedent for a mixed
|
|
953
|
+
// barrel above.
|
|
954
|
+
//
|
|
955
|
+
// apps/api/src/routes/project-listings/respond.ts (`sendValidated`) IS
|
|
956
|
+
// listed, even though it is ALSO imported directly by the tenant routes
|
|
957
|
+
// get.ts/list.ts/patch.ts/patch-copy.ts (multi-tenant, Pro Plus territory
|
|
958
|
+
// — grep-verified, four direct importers outside this module). Same D6
|
|
959
|
+
// reasoning as the services below: every non-territory consumer is a
|
|
960
|
+
// strictly higher (Pro Plus) level, never Free, so this module owns the
|
|
961
|
+
// file and #5367 records the prerequisite.
|
|
962
|
+
//
|
|
963
|
+
// Ten services below are reached from Pro Plus's project-listings tenant
|
|
964
|
+
// routes (get.ts/list.ts/patch.ts/patch-copy.ts) or commerce's recommender,
|
|
965
|
+
// directly or transitively through project-listing-decision.ts /
|
|
966
|
+
// project-listing-flow.ts — grep-verified, not carried over from the
|
|
967
|
+
// spec's table (which independently reaches the same eight; this pass adds
|
|
968
|
+
// waitlist-scoring.ts and playbook-compile.ts, both of which the finalize
|
|
969
|
+
// scorecard already flagged as under-described). D6's rule: this module
|
|
970
|
+
// owns the shared file because every OTHER consumer is a superset level
|
|
971
|
+
// (OFFERINGS.md §4a Table 1 — Pro Plus contains Pro; the commerce add-on is
|
|
972
|
+
// never sold at Free); #5364/#5367 each record this module as a
|
|
973
|
+
// prerequisite of the routes that reach it rather than re-homing the file.
|
|
974
|
+
// - flow-engine.ts — pro-plus, via project-listing-flow.ts:49 ←
|
|
975
|
+
// project-listing-decision.ts:81 ← patch.ts:38
|
|
976
|
+
// - waitlist-scoring.ts — pro-plus, transitively (sole importer is
|
|
977
|
+
// flow-engine.ts:56, which is itself shared)
|
|
978
|
+
// - playbook-compile.ts — pro-plus, transitively (imported by
|
|
979
|
+
// waitlist-scoring.ts:33 and, in-module, by
|
|
980
|
+
// playbook-render.ts:62 and
|
|
981
|
+
// routes/deliverables/index.ts:44)
|
|
982
|
+
// - project-listings.ts, listing-config.ts, project-listing-decision.ts,
|
|
983
|
+
// project-listing-flow.ts, project-listing-issue.ts,
|
|
984
|
+
// waitlist-experiments.ts — pro-plus, direct or transitive via the
|
|
985
|
+
// decision/flow chain above
|
|
986
|
+
// - deliverable-fulfillment.ts — commerce, via recommender-capture.ts:70.
|
|
987
|
+
// NOT ADDED to ownedFiles below, unlike the rest of this list — spec
|
|
988
|
+
// §5.4's escalation boundary fires for this ONE file: D6's premise is
|
|
989
|
+
// "every OTHER consumer is a superset level, never Free," but
|
|
990
|
+
// recommender-capture.ts (and recommender.ts above it, and server.ts
|
|
991
|
+
// above THAT via a plain static import) is UNCONDITIONAL today — #5364
|
|
992
|
+
// has not landed to gate it behind isModuleEnabled("commerce"). Adding
|
|
993
|
+
// this file to ownedFiles made `paidModuleTemplateExclusions()`'s
|
|
994
|
+
// import-graph closure exclude recommender.ts, then server.ts itself,
|
|
995
|
+
// from every keyless scaffold (empirically found, #5366 resume pass) —
|
|
996
|
+
// a base-breaking regression a template snapshot must never produce.
|
|
997
|
+
// Revert this line once #5364 lands and gates the recommender routes;
|
|
998
|
+
// until then the file ships in every scaffold regardless of module
|
|
999
|
+
// selection, exactly as it did before this card (a narrower, temporary
|
|
1000
|
+
// miss than the one D6 accepts on purpose for the other nine).
|
|
1001
|
+
//
|
|
1002
|
+
// apps/api/src/services/listing-promotion.ts has ZERO production
|
|
1003
|
+
// importers anywhere in the repo (only its own test) — confirmed dead code
|
|
1004
|
+
// (spec §7 Q5). Listed anyway: it is listing code by subject, D-48 places
|
|
1005
|
+
// the instrument here, and a reachability grep cannot place an unreached
|
|
1006
|
+
// file — this is a recorded pre-existing defect, not fixed by this card.
|
|
1007
|
+
//
|
|
1008
|
+
// apps/api/src/bin/deliverable-upload.ts imports only `prisma` (no moved
|
|
1009
|
+
// service) but is a deliverables CLI a Free starter should not ship —
|
|
1010
|
+
// listed by subject, not by the import-criterion the other six bins meet.
|
|
1011
|
+
//
|
|
1012
|
+
// apps/web: FlowStepperClient.tsx, ResultsClient.tsx and
|
|
1013
|
+
// ListingApplicationClient.tsx are this module's OWN files (below), so
|
|
1014
|
+
// their packages/ui imports (FlowStepper, FlowSidePanel,
|
|
1015
|
+
// ListingApplicationFlow) are in-module edges, not Free ones, despite
|
|
1016
|
+
// living under apps/web rather than apps-paid.
|
|
1017
|
+
//
|
|
1018
|
+
// packages/ui: eleven components (D8) plus the NEW slice registration
|
|
1019
|
+
// entry point (D8a, mirroring sections/slices/scheduling.ts). Four of the
|
|
1020
|
+
// eleven (ProjectListingShelves, ListingPrivacyNotice, ProjectListingCard,
|
|
1021
|
+
// ResultsReveal) had no consumer anywhere IN THIS REPO at D8 authoring
|
|
1022
|
+
// time — grep-confirmed, a module-boundary fact only in-repo. Three of the
|
|
1023
|
+
// four (ProjectListingShelves, ProjectListingCard, ListingPrivacyNotice —
|
|
1024
|
+
// plus the ListingWindowBand type ProjectListingCard exports) are, in
|
|
1025
|
+
// fact, consumed CROSS-ORG: the samhenry site (salessmyth org) imports all
|
|
1026
|
+
// four from the signal-collectors slice's re-export entry point
|
|
1027
|
+
// (packages/ui/src/sections/slices/signal-collectors.ts, rules/cross-org-
|
|
1028
|
+
// sharing.md), which #5488 additionally re-exports them from so that
|
|
1029
|
+
// consumer can reach them by subpath. "No consumer anywhere in the repo"
|
|
1030
|
+
// was therefore true in-repo and false across the org boundary — not a
|
|
1031
|
+
// reachability fact a repo-scoped grep can see. ResultsReveal remains the
|
|
1032
|
+
// one component of the four with no known consumer anywhere (in-repo or
|
|
1033
|
+
// out) and is NOT re-exported by #5488 — it is not this card's claim to
|
|
1034
|
+
// make it non-orphaned. D8's placement rule (by subject — project-listing
|
|
1035
|
+
// / results-reveal UI — rather than by reachability, since reachability
|
|
1036
|
+
// cannot place an unreached file either) is unchanged and still governs
|
|
1037
|
+
// where all eleven live.
|
|
1038
|
+
"signal-collectors": {
|
|
1039
|
+
ownedFiles: [
|
|
1040
|
+
"apps/api/src/routes/flows/index.ts",
|
|
1041
|
+
// README.md documents the flows rate-limit rationale (#4730) — not a
|
|
1042
|
+
// test/generated file, and its absence is exactly what left a stray
|
|
1043
|
+
// apps/api/src/routes/flows/ directory in a keyless templates/ snapshot
|
|
1044
|
+
// (empirically found, #5366) since the import-graph closure below only
|
|
1045
|
+
// scans source extensions, never markdown.
|
|
1046
|
+
"apps/api/src/routes/flows/README.md",
|
|
1047
|
+
"apps/api/src/routes/deliverables/index.ts",
|
|
1048
|
+
"apps/api/src/routes/slack/index.ts",
|
|
1049
|
+
"apps/api/src/routes/slack/actions.ts",
|
|
1050
|
+
"apps/api/src/routes/waitlist-signups/index.ts",
|
|
1051
|
+
// apps/api/src/routes/project-listings/{start,patch-draft,submit,public,
|
|
1052
|
+
// me,respond,resume-token}.ts and services/{project-listings,
|
|
1053
|
+
// listing-config}.ts deliberately NOT listed — see the comment above
|
|
1054
|
+
// this array (D-48/#5366 escalation: the mixed-barrel `index.ts` in
|
|
1055
|
+
// that directory is reached from server.ts by a plain, literal
|
|
1056
|
+
// `import()` for multi-tenant's tenant routes, and statically imports
|
|
1057
|
+
// all nine of these files itself, so `paidModuleTemplateExclusions()`'s
|
|
1058
|
+
// import-graph closure excluded `index.ts`, then `server.ts` itself,
|
|
1059
|
+
// from every keyless scaffold (empirically found, #5366 resume pass,
|
|
1060
|
+
// same failure mode as the deliverable-fulfillment.ts case below but a
|
|
1061
|
+
// permanent structural one rather than a temporal gap pending another
|
|
1062
|
+
// PR). This is also the ORIGINAL multi-tenant/#5088 card's own
|
|
1063
|
+
// conclusion about these same nine files (lines 556-571 above) —
|
|
1064
|
+
// D-48 moves their tier ownership to signal-collectors but not their
|
|
1065
|
+
// must-ship-unconditionally constraint. Registration of every route
|
|
1066
|
+
// that reaches them stays gated by `isModuleEnabled("signal-collectors")`
|
|
1067
|
+
// in server.ts; only the source files themselves ship regardless.
|
|
1068
|
+
"apps/api/src/services/flow-engine.ts",
|
|
1069
|
+
"apps/api/src/services/flow-aggregate.ts",
|
|
1070
|
+
"apps/api/src/services/waitlist-signups.ts",
|
|
1071
|
+
"apps/api/src/services/waitlist-scoring.ts",
|
|
1072
|
+
"apps/api/src/services/playbook-compile.ts",
|
|
1073
|
+
"apps/api/src/services/playbook-render.ts",
|
|
1074
|
+
"apps/api/src/services/listing-csv-sweep.ts",
|
|
1075
|
+
"apps/api/src/services/waitlist-followup.ts",
|
|
1076
|
+
"apps/api/src/services/listing-promotion.ts",
|
|
1077
|
+
"apps/api/src/services/project-listing-decision.ts",
|
|
1078
|
+
"apps/api/src/services/project-listing-flow.ts",
|
|
1079
|
+
"apps/api/src/services/project-listing-issue.ts",
|
|
1080
|
+
"apps/api/src/services/waitlist-experiments.ts",
|
|
1081
|
+
// deliverable-fulfillment.ts deliberately NOT listed — see the comment
|
|
1082
|
+
// above this array (spec §5.4 escalation boundary, temporary pending #5364).
|
|
1083
|
+
"apps/api/src/bin/deliverable-resend.ts",
|
|
1084
|
+
"apps/api/src/bin/deliverable-upload.ts",
|
|
1085
|
+
"apps/api/src/bin/session-retention-sweep.ts",
|
|
1086
|
+
"apps/api/src/bin/seed-presets.ts",
|
|
1087
|
+
"apps/api/src/bin/listing-csv-sweep.ts",
|
|
1088
|
+
"apps/api/src/bin/followup-sweep.ts",
|
|
1089
|
+
"apps/api/src/bin/seed-waitlist-experiments.ts",
|
|
1090
|
+
"apps/mcp/src/tools/get_flow.ts",
|
|
1091
|
+
"apps/mcp/src/tools/submit_flow_step.ts",
|
|
1092
|
+
// apps/web/app/[locale]/flows/** deliberately NOT listed here (unlike
|
|
1093
|
+
// the docs-blog precedent's own `blog`/`docs` page.tsx entries above),
|
|
1094
|
+
// even though every file under it is signal-collectors territory and
|
|
1095
|
+
// still carries its own `oss: false` marker for the OSS-strip. Every
|
|
1096
|
+
// one of these files is ALREADY excluded from a keyless scaffold by the
|
|
1097
|
+
// pre-existing, independent `MODULE_SURFACES["signal-collectors"] =
|
|
1098
|
+
// ["flows"]` → `excludedRoutePaths()` mechanism (#4154), which removes
|
|
1099
|
+
// the WHOLE `apps/web/app/[locale]/flows` directory at copy time
|
|
1100
|
+
// whenever the "flows" surface isn't selected — and `resolveSurfaces`
|
|
1101
|
+
// refuses `--surfaces flows` without the module (#5365 FR5/D12), so
|
|
1102
|
+
// there is no way to reach "flows carried, signal-collectors absent".
|
|
1103
|
+
// Adding them to `ownedFiles` ALSO excludes them from `templates/`
|
|
1104
|
+
// itself (build-templates.mjs), which broke `sync-routes`'s pre-#5366
|
|
1105
|
+
// upgrade-path fixture (`flows/[slug]/results/[payload]`, #4891/#4986)
|
|
1106
|
+
// and — more importantly — would silently strip a REAL consumer's
|
|
1107
|
+
// `sync-routes` tool of the ability to ever restore these files after
|
|
1108
|
+
// scaffolding, since that tool diffs against `templates/` alone and has
|
|
1109
|
+
// no module/licence concept of its own (empirically found, #5366 resume
|
|
1110
|
+
// pass). `projects/apply/ListingApplicationClient.tsx` below is
|
|
1111
|
+
// different in kind: it sits under the UNRELATED "projects" content
|
|
1112
|
+
// surface's URL segment, which `excludedRoutePaths` does not gate on
|
|
1113
|
+
// signal-collectors at all, so it genuinely needs `ownedFiles` to be
|
|
1114
|
+
// excluded from a keyless scaffold — see `sync-routes.ts`'s
|
|
1115
|
+
// `NESTED_FOREIGN_MODULE_ENTRIES` for the companion fix that keeps its
|
|
1116
|
+
// presence from falsely reading as "projects carried".
|
|
1117
|
+
"apps/web/app/[locale]/projects/apply/ListingApplicationClient.tsx",
|
|
1118
|
+
"packages/ui/src/sections/ListingApplicationFlow.tsx",
|
|
1119
|
+
"packages/ui/src/sections/ProjectListingShelves.tsx",
|
|
1120
|
+
"packages/ui/src/sections/FlowStepper.tsx",
|
|
1121
|
+
"packages/ui/src/blocks/FlowSidePanel.tsx",
|
|
1122
|
+
"packages/ui/src/blocks/ListingFullPreview.tsx",
|
|
1123
|
+
"packages/ui/src/blocks/ListingQuestionReview.tsx",
|
|
1124
|
+
"packages/ui/src/blocks/ListingTilePreview.tsx",
|
|
1125
|
+
"packages/ui/src/blocks/ListingPrivacyNotice.tsx",
|
|
1126
|
+
"packages/ui/src/blocks/ProjectListingCard.tsx",
|
|
1127
|
+
"packages/ui/src/blocks/ResponseChart.tsx",
|
|
1128
|
+
"packages/ui/src/blocks/ResultsReveal.tsx",
|
|
1129
|
+
"packages/ui/src/sections/slices/signal-collectors.ts",
|
|
1130
|
+
],
|
|
1131
|
+
// pageContributions (spec 5478; parent § D6 shape 2) — the three flow
|
|
1132
|
+
// routes, named exactly as `surfaces.ts`'s ROUTE_SINCE keys name them.
|
|
1133
|
+
// ROWS AND SEED ONLY: unlike docs-blog and scheduling above, this module's
|
|
1134
|
+
// route code is deliberately NOT in `ownedFiles` (see the comment inside
|
|
1135
|
+
// that array). The first two rows' code reaches a scaffold from the
|
|
1136
|
+
// `templates/` snapshot, retained because the `flows` surface is enabled;
|
|
1137
|
+
// the results row's code is `commerce`'s (`commerce.ownedFiles` carries
|
|
1138
|
+
// `results/[payload]/page.tsx` + its two client files below, and
|
|
1139
|
+
// `paidModuleTemplateExclusions` strips every paid module's owned files
|
|
1140
|
+
// from the snapshot unconditionally), so that one row rides a DIFFERENT
|
|
1141
|
+
// module's bundle — recorded in spec 5478 § 8 item 1, whose delivery
|
|
1142
|
+
// consequence is #5481's and #5464's. Declaring the rows here changes none
|
|
1143
|
+
// of it: a contribution is data, and which delivery shape carries the code
|
|
1144
|
+
// is a property of the module, not of the contribution.
|
|
1145
|
+
pageContributions: [
|
|
1146
|
+
{ route: "/flows/[slug]" },
|
|
1147
|
+
{ route: "/flows/[slug]/start" },
|
|
1148
|
+
{ route: "/flows/[slug]/results/[payload]" },
|
|
1149
|
+
],
|
|
1150
|
+
},
|
|
1151
|
+
// ── commerce — per-site paid add-on (D-47, amending D-26) ─────────────────
|
|
1152
|
+
//
|
|
1153
|
+
// Checkout, the Stripe webhook receiver, flow checkouts and the recommender
|
|
1154
|
+
// (D-47's disposition sentence, verbatim). The base API keeps only
|
|
1155
|
+
// `isModuleEnabled("commerce")`; every registration loads through
|
|
1156
|
+
// `SLICE_PLUGINS` (server.ts). `apps.api.may_import_from` names
|
|
1157
|
+
// `packages/stripe-client` — the module's own package (D5) — mirroring the
|
|
1158
|
+
// `multi-tenant`/`scheduling` slices' identical entry, which already
|
|
1159
|
+
// document "checkout moved to the commerce module (D-47)" for the same
|
|
1160
|
+
// reason those two slices state theirs: `deriveArchitecture` merges `api`
|
|
1161
|
+
// blocks with `Object.assign`, so every slice declaring `api` must agree.
|
|
1162
|
+
//
|
|
1163
|
+
// Q1 (spec §7): a `multi-tenant` deployment using the Stripe billing portal
|
|
1164
|
+
// or org-scoped webhook routing (`routes/billing/portal.ts`,
|
|
1165
|
+
// `routes/webhooks/stripe.ts`'s org-billing branch) also depends on
|
|
1166
|
+
// `lib/stripe.ts` and the webhook receiver this module owns — declared
|
|
1167
|
+
// here, not engineered around.
|
|
1168
|
+
commerce: {
|
|
1169
|
+
apps: {
|
|
1170
|
+
api: {
|
|
1171
|
+
path: "apps/api",
|
|
1172
|
+
description: "Public HTTP API — routes + services (Fastify). Owns checkout, the Stripe webhook receiver, flow checkouts and the recommender (D-47) — the Stripe setup and stripe-client's sole apps/api reach.",
|
|
1173
|
+
may_import_from: [
|
|
1174
|
+
"database",
|
|
1175
|
+
"packages/analytics",
|
|
1176
|
+
"packages/email",
|
|
1177
|
+
"packages/license",
|
|
1178
|
+
"packages/schema",
|
|
1179
|
+
"packages/site-config",
|
|
1180
|
+
"packages/stripe-client",
|
|
1181
|
+
"packages/validation",
|
|
1182
|
+
],
|
|
1183
|
+
may_not_import_from: [
|
|
1184
|
+
"apps/mcp",
|
|
1185
|
+
"apps/web",
|
|
1186
|
+
"packages/theme",
|
|
1187
|
+
"packages/ui",
|
|
1188
|
+
],
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
packages: {
|
|
1192
|
+
// Duplicated VERBATIM from the multi-tenant slice's own "stripe-client"
|
|
1193
|
+
// entry (§7 Q1 — a multi-tenant deployment using the Stripe billing
|
|
1194
|
+
// portal or org-billing webhook routing also installs commerce, so
|
|
1195
|
+
// both slices can be selected together) — the same order-independence
|
|
1196
|
+
// reason the multi-tenant/scheduling slices state for `validation`
|
|
1197
|
+
// below: `deriveArchitecture` merges `packages` blocks with
|
|
1198
|
+
// `Object.assign`, so two slices declaring this key differently would
|
|
1199
|
+
// make the derivation depend on module order.
|
|
1200
|
+
"stripe-client": {
|
|
1201
|
+
description: "Stripe SDK wrapper + webhook signature verification",
|
|
1202
|
+
may_import_from: ["packages/validation"],
|
|
1203
|
+
},
|
|
1204
|
+
// Duplicated VERBATIM from the marketing slice for the same
|
|
1205
|
+
// order-independence reason the multi-tenant/scheduling slices state.
|
|
1206
|
+
validation: {
|
|
1207
|
+
description: "Zod schemas + shared types",
|
|
1208
|
+
may_import_from: [],
|
|
1209
|
+
},
|
|
1210
|
+
},
|
|
1211
|
+
// webImports omitted (§4.4): no commerce component reaches apps/web
|
|
1212
|
+
// through a package apps/web does not already import — packages/ui is
|
|
1213
|
+
// base, and architecture.yaml already forbids apps/web -> stripe-client.
|
|
1214
|
+
forbiddenPatterns: [
|
|
1215
|
+
{
|
|
1216
|
+
pattern: STRIPE_LIVE_KEY_PATTERN,
|
|
1217
|
+
paths_excluded: ["apps/api/**"],
|
|
1218
|
+
reason: "The commerce credential belongs to apps/api, behind assertSandboxKey's sandbox-only allow-list. A live-mode-shaped key anywhere else is a leak, not a config choice",
|
|
1219
|
+
},
|
|
1220
|
+
],
|
|
1221
|
+
// ownedFiles (S1, #5088). SOURCE files only (#5182 D6) — no __tests__/,
|
|
1222
|
+
// no .stories.tsx, no .text.ts... except .text.ts siblings ARE source
|
|
1223
|
+
// (they ship as runtime copy modules, not test fixtures), so the ten
|
|
1224
|
+
// annotated below are listed. 42 in all: 9 apps/api + 26 packages/ui
|
|
1225
|
+
// (15 components + 10 .text.ts siblings + this slice's own
|
|
1226
|
+
// sections/slices/commerce.ts) + 7 apps/web.
|
|
1227
|
+
ownedFiles: [
|
|
1228
|
+
"apps/api/src/lib/stripe.ts",
|
|
1229
|
+
"apps/api/src/routes/checkout/index.ts",
|
|
1230
|
+
"apps/api/src/routes/checkout/sessions.ts",
|
|
1231
|
+
"apps/api/src/routes/webhooks/index.ts",
|
|
1232
|
+
"apps/api/src/routes/webhooks/stripe.ts",
|
|
1233
|
+
// README.md documents the Stripe webhook receiver — not a test/
|
|
1234
|
+
// generated file, and its absence is exactly what left a stray
|
|
1235
|
+
// apps/api/src/routes/webhooks/ directory in a keyless templates/
|
|
1236
|
+
// snapshot (empirically found, #5364 build pass): the import-graph
|
|
1237
|
+
// closure only scans source extensions, never markdown, so once
|
|
1238
|
+
// index.ts and stripe.ts are excluded this is the one file left
|
|
1239
|
+
// behind. Same defect class #5366 found and fixed the same way for
|
|
1240
|
+
// routes/flows/README.md — see that entry above.
|
|
1241
|
+
"apps/api/src/routes/webhooks/README.md",
|
|
1242
|
+
"apps/api/src/routes/flow-checkouts/index.ts",
|
|
1243
|
+
"apps/api/src/routes/flows/recommender.ts",
|
|
1244
|
+
"apps/api/src/services/recommender-capture.ts",
|
|
1245
|
+
"apps/api/src/services/flow-checkouts.ts",
|
|
1246
|
+
"packages/ui/src/blocks/CheckoutForm.tsx",
|
|
1247
|
+
"packages/ui/src/blocks/CheckoutForm.text.ts",
|
|
1248
|
+
"packages/ui/src/blocks/CheckoutPriceCard.tsx",
|
|
1249
|
+
"packages/ui/src/blocks/PaymentLinkCard.tsx",
|
|
1250
|
+
"packages/ui/src/blocks/PaymentLinkCard.text.ts",
|
|
1251
|
+
"packages/ui/src/blocks/PaymentLinkForm.tsx",
|
|
1252
|
+
"packages/ui/src/blocks/PaymentLinkForm.text.ts",
|
|
1253
|
+
"packages/ui/src/blocks/PaymentLinkList.tsx",
|
|
1254
|
+
"packages/ui/src/blocks/InvoiceForm.tsx",
|
|
1255
|
+
"packages/ui/src/blocks/InvoiceForm.text.ts",
|
|
1256
|
+
"packages/ui/src/blocks/InvoiceList.tsx",
|
|
1257
|
+
"packages/ui/src/blocks/InvoiceList.text.ts",
|
|
1258
|
+
"packages/ui/src/blocks/SubscriptionStatus.tsx",
|
|
1259
|
+
"packages/ui/src/blocks/SubscriptionStatus.text.ts",
|
|
1260
|
+
"packages/ui/src/blocks/StripeActionButton.tsx",
|
|
1261
|
+
"packages/ui/src/blocks/PaymentStatusBadge.tsx",
|
|
1262
|
+
"packages/ui/src/blocks/PaymentStatusBadge.text.ts",
|
|
1263
|
+
"packages/ui/src/blocks/PaymentResult.tsx",
|
|
1264
|
+
"packages/ui/src/blocks/PaymentResult.text.ts",
|
|
1265
|
+
"packages/ui/src/blocks/PortalEntry.tsx",
|
|
1266
|
+
"packages/ui/src/panels/InvoiceDetail.tsx",
|
|
1267
|
+
"packages/ui/src/panels/InvoiceDetail.text.ts",
|
|
1268
|
+
"packages/ui/src/sections/PaymentReceipt.tsx",
|
|
1269
|
+
"packages/ui/src/sections/PricingTable.tsx",
|
|
1270
|
+
"packages/ui/src/sections/PricingTable.text.ts",
|
|
1271
|
+
"packages/ui/src/sections/slices/commerce.ts",
|
|
1272
|
+
"apps/web/app/[locale]/flows/[slug]/checkout.actions.ts",
|
|
1273
|
+
"apps/web/app/[locale]/flows/[slug]/results/[payload]/page.tsx",
|
|
1274
|
+
"apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsClient.tsx",
|
|
1275
|
+
"apps/web/app/[locale]/flows/[slug]/results/[payload]/ResultsEmailStep.tsx",
|
|
1276
|
+
"apps/web/app/[locale]/dev/purchase/page.tsx",
|
|
1277
|
+
"apps/web/app/[locale]/dev/purchase/error.tsx",
|
|
1278
|
+
"apps/web/app/[locale]/dev/purchase/purchase.actions.ts",
|
|
1279
|
+
],
|
|
1280
|
+
// The scaffold-commerce authoring skill (D-47, #5449): moved by `git mv`
|
|
1281
|
+
// out of the Free starter's `templates/.claude/skills/` (never stripped —
|
|
1282
|
+
// it sits outside build-templates.mjs's SNAPSHOT_DIRS/overlay, so
|
|
1283
|
+
// ownedFiles/paidModuleTemplateExclusions cannot reach it) to
|
|
1284
|
+
// `module-templates/commerce/.claude/skills/scaffold-commerce/`, and
|
|
1285
|
+
// delivered into a keyed scaffold by `installMap` instead. Ten literal
|
|
1286
|
+
// entries, not one directory entry: `extractModuleBundle`'s
|
|
1287
|
+
// `validateInstallMap` requires every source to be a FILE the bundle
|
|
1288
|
+
// produced (`extract-module-bundle.ts`'s `!sourceStat.isFile()` check) —
|
|
1289
|
+
// a directory source is rejected outright.
|
|
1290
|
+
installMap: {
|
|
1291
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/SKILL.md": ".claude/skills/scaffold-commerce/SKILL.md",
|
|
1292
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/references/lookup-keys-template.md": ".claude/skills/scaffold-commerce/references/lookup-keys-template.md",
|
|
1293
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/references/marketplace-brand-pages.md": ".claude/skills/scaffold-commerce/references/marketplace-brand-pages.md",
|
|
1294
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/checkout-route.template.ts": ".claude/skills/scaffold-commerce/templates/checkout-route.template.ts",
|
|
1295
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/invoice-route.template.ts": ".claude/skills/scaffold-commerce/templates/invoice-route.template.ts",
|
|
1296
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl": ".claude/skills/scaffold-commerce/templates/marketplace-cta-route.tsx.tmpl",
|
|
1297
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/payment-link-route.template.ts": ".claude/skills/scaffold-commerce/templates/payment-link-route.template.ts",
|
|
1298
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/portal-route.template.ts": ".claude/skills/scaffold-commerce/templates/portal-route.template.ts",
|
|
1299
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/stripe-config.template.ts": ".claude/skills/scaffold-commerce/templates/stripe-config.template.ts",
|
|
1300
|
+
"packages/create-ailk/module-templates/commerce/.claude/skills/scaffold-commerce/templates/subscription-route.template.ts": ".claude/skills/scaffold-commerce/templates/subscription-route.template.ts",
|
|
1301
|
+
},
|
|
645
1302
|
},
|
|
646
1303
|
};
|
|
647
1304
|
/**
|
|
@@ -661,3 +1318,141 @@ export function normalizeModules(modules) {
|
|
|
661
1318
|
}
|
|
662
1319
|
return RECOGNIZED_MODULES.filter((m) => requested.has(m));
|
|
663
1320
|
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Template-relative paths that must never be written into `templates/` for a
|
|
1323
|
+
* keyless starter: every PAID module's `ownedFiles` entry that resolves under
|
|
1324
|
+
* a `build-templates` snapshot root, plus every file under those roots that
|
|
1325
|
+
* imports one (transitively), which would otherwise ship dangling.
|
|
1326
|
+
*
|
|
1327
|
+
* This is the SINGLE starter-removal input for all four R1 extractions
|
|
1328
|
+
* (#5364 commerce, #5365 docs + blog, #5366 signal-collectors, #5367 Pro Plus
|
|
1329
|
+
* + scheduling). A module joins by gaining `ownedFiles` entries — never by
|
|
1330
|
+
* adding a path to a list here.
|
|
1331
|
+
*
|
|
1332
|
+
* The input is `ownedFiles`, NOT the `oss: false` marker set. The two answer
|
|
1333
|
+
* different questions: the strip's authority is their union (see the
|
|
1334
|
+
* `ownedFiles` doc above), while the STARTER's authority is `ownedFiles`
|
|
1335
|
+
* alone. The marker set includes the content-write trio, which D-44 keeps in
|
|
1336
|
+
* public code licence-checked at runtime — deriving the starter exclusion from
|
|
1337
|
+
* markers would remove a surface D-44 says must ship.
|
|
1338
|
+
*
|
|
1339
|
+
* Entries outside the snapshot roots — every `packages/**` path, and the paid
|
|
1340
|
+
* app roots — are not snapshotted at all and are filtered here rather than
|
|
1341
|
+
* special-cased at the call site. Today every glob entry is also out-of-root,
|
|
1342
|
+
* so globs never reach the literal-path matcher below.
|
|
1343
|
+
*
|
|
1344
|
+
* @param snapshotRoots repo-relative roots `build-templates.mjs` snapshots.
|
|
1345
|
+
* @param repoRoot absolute path to the monorepo root, for the import scan.
|
|
1346
|
+
* Passed in rather than derived from `import.meta.url`, which ts-jest cannot
|
|
1347
|
+
* load — the same reason `sync-routes.ts` documents for staying pure.
|
|
1348
|
+
*/
|
|
1349
|
+
export function paidModuleTemplateExclusions(snapshotRoots, repoRoot) {
|
|
1350
|
+
const roots = new Set(snapshotRoots);
|
|
1351
|
+
const excluded = new Set();
|
|
1352
|
+
for (const moduleName of PAID_MODULES) {
|
|
1353
|
+
for (const owned of MODULE_SLICES[moduleName]?.ownedFiles ?? []) {
|
|
1354
|
+
const rel = owned.split(sep).join("/");
|
|
1355
|
+
if (!roots.has(rel.split("/")[0] ?? ""))
|
|
1356
|
+
continue;
|
|
1357
|
+
if (rel.includes("*"))
|
|
1358
|
+
continue;
|
|
1359
|
+
excluded.add(rel);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
// Companion closure by import graph, to a fixed point — never a filename
|
|
1363
|
+
// stem rule (#5182 D7), which misses eleven files and over-marks three.
|
|
1364
|
+
const candidates = listFilesUnder(repoRoot, [...roots]);
|
|
1365
|
+
for (;;) {
|
|
1366
|
+
let grew = false;
|
|
1367
|
+
for (const file of candidates) {
|
|
1368
|
+
if (excluded.has(file))
|
|
1369
|
+
continue;
|
|
1370
|
+
const imports = relativeImportsOf(join(repoRoot, file));
|
|
1371
|
+
for (const spec of imports) {
|
|
1372
|
+
const target = resolveRelativeImport(file, spec, candidates);
|
|
1373
|
+
if (target !== undefined && excluded.has(target)) {
|
|
1374
|
+
excluded.add(file);
|
|
1375
|
+
grew = true;
|
|
1376
|
+
break;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
if (!grew)
|
|
1381
|
+
break;
|
|
1382
|
+
}
|
|
1383
|
+
return [...excluded].sort();
|
|
1384
|
+
}
|
|
1385
|
+
const SOURCE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1386
|
+
/** Every source file under the given repo-relative roots, as "/"-joined paths. */
|
|
1387
|
+
function listFilesUnder(repoRoot, roots) {
|
|
1388
|
+
const out = new Set();
|
|
1389
|
+
const skip = new Set(["node_modules", ".next", "dist", ".turbo", ".source"]);
|
|
1390
|
+
const stack = roots.map((r) => r);
|
|
1391
|
+
while (stack.length > 0) {
|
|
1392
|
+
const rel = stack.pop();
|
|
1393
|
+
const abs = join(repoRoot, rel);
|
|
1394
|
+
let entries;
|
|
1395
|
+
try {
|
|
1396
|
+
entries = readdirSync(abs, { withFileTypes: true });
|
|
1397
|
+
}
|
|
1398
|
+
catch {
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
for (const entry of entries) {
|
|
1402
|
+
if (skip.has(entry.name))
|
|
1403
|
+
continue;
|
|
1404
|
+
const childRel = `${rel}/${entry.name}`;
|
|
1405
|
+
if (entry.isDirectory())
|
|
1406
|
+
stack.push(childRel);
|
|
1407
|
+
else if (SOURCE_EXTS.some((e) => entry.name.endsWith(e)))
|
|
1408
|
+
out.add(childRel);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
return out;
|
|
1412
|
+
}
|
|
1413
|
+
/** The relative import specifiers a source file names (static imports + re-exports). */
|
|
1414
|
+
function relativeImportsOf(absPath) {
|
|
1415
|
+
let src;
|
|
1416
|
+
try {
|
|
1417
|
+
src = readFileSync(absPath, "utf8");
|
|
1418
|
+
}
|
|
1419
|
+
catch {
|
|
1420
|
+
return [];
|
|
1421
|
+
}
|
|
1422
|
+
const out = [];
|
|
1423
|
+
for (const m of src.matchAll(/(?:^|\n)\s*(?:import|export)[\s\S]{0,400}?from\s*["'](\.[^"']*)["']/g))
|
|
1424
|
+
out.push(m[1]);
|
|
1425
|
+
for (const m of src.matchAll(/\bimport\s*\(\s*["'](\.[^"']*)["']\s*\)/g))
|
|
1426
|
+
out.push(m[1]);
|
|
1427
|
+
return out;
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Resolve a relative specifier against the candidate set. TypeScript ESM writes
|
|
1431
|
+
* `./x.js` for `./x.ts`, so the `.js` → `.ts`/`.tsx` rewrite is the common case.
|
|
1432
|
+
*/
|
|
1433
|
+
function resolveRelativeImport(fromFile, spec, candidates) {
|
|
1434
|
+
const base = posixJoin(dirname(fromFile.split("/").join(sep)), spec);
|
|
1435
|
+
const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
|
|
1436
|
+
for (const cand of [
|
|
1437
|
+
base,
|
|
1438
|
+
...SOURCE_EXTS.map((e) => stem + e),
|
|
1439
|
+
...SOURCE_EXTS.map((e) => `${stem}/index${e}`),
|
|
1440
|
+
])
|
|
1441
|
+
if (candidates.has(cand))
|
|
1442
|
+
return cand;
|
|
1443
|
+
return undefined;
|
|
1444
|
+
}
|
|
1445
|
+
/** Join and normalize a "/"-separated path, resolving `.` and `..` segments. */
|
|
1446
|
+
function posixJoin(dir, spec) {
|
|
1447
|
+
const parts = `${dir.split(sep).join("/")}/${spec}`.split("/");
|
|
1448
|
+
const out = [];
|
|
1449
|
+
for (const part of parts) {
|
|
1450
|
+
if (part === "" || part === ".")
|
|
1451
|
+
continue;
|
|
1452
|
+
if (part === "..")
|
|
1453
|
+
out.pop();
|
|
1454
|
+
else
|
|
1455
|
+
out.push(part);
|
|
1456
|
+
}
|
|
1457
|
+
return out.join("/");
|
|
1458
|
+
}
|