create-ailk 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -20
- package/component-catalog.json +3 -3
- package/component-catalog.md +3 -3
- package/dist/add-module.js +4 -2
- package/dist/add-route.d.ts +12 -1
- package/dist/add-route.js +31 -3
- package/dist/cli.js +12 -7
- package/dist/derive-architecture.d.ts +3 -4
- package/dist/derive-architecture.js +65 -29
- package/dist/lib/design-checks.d.ts +9 -4
- package/dist/lib/design-checks.js +13 -7
- package/dist/lib/extract-module-bundle.js +29 -2
- package/dist/lib/fetch-template-snapshot.d.ts +1 -1
- package/dist/lib/fetch-template-snapshot.js +7 -3
- package/dist/lib/import-graph.d.ts +1 -1
- package/dist/lib/import-graph.js +4 -4
- package/dist/lib/module-license-gate.d.ts +12 -1
- package/dist/lib/module-license-gate.js +34 -12
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +117 -550
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/surfaces.js +10 -2
- package/dist/template-record.d.ts +14 -4
- package/dist/template-record.js +23 -5
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +31 -19
- package/dist/update.d.ts +10 -1
- package/dist/update.js +540 -16
- package/package.json +3 -3
- package/release-scope.json +1 -1
- package/templates/.claude/cloudparity-repo-hooks.json +5 -0
- package/templates/.claude/hooks/template-guard.sh +137 -0
- package/templates/.claude/rules/extending.md +106 -0
- package/templates/.claude/rules/loop-contract.md +2 -2
- package/templates/.claude/settings.json +11 -0
- package/templates/.env.example +5 -5
- package/templates/.github/workflows/ci.yml +7 -4
- package/templates/CLAUDE.md +11 -1
- package/templates/CONVENTIONS.md +8 -10
- package/templates/README.md +14 -13
- package/templates/apps/api/.env.example +2 -2
- package/templates/apps/api/CLAUDE.md +102 -76
- package/templates/apps/api/jest.config.cjs +15 -5
- package/templates/apps/api/package.json +16 -20
- package/templates/apps/api/src/__tests__/trusted-origins.server.test.ts +2 -2
- package/templates/apps/api/src/__tests__/vercel-handler.test.ts +4 -4
- package/templates/apps/api/src/index.ts +1 -1
- package/templates/apps/api/src/lib/__mocks__/prisma.ts +3 -3
- package/templates/apps/api/src/modules/commerce.ts +10 -0
- package/templates/apps/api/src/modules/content-write.ts +10 -0
- package/templates/apps/api/src/modules/multi-tenant.ts +10 -0
- package/templates/apps/api/src/modules/scheduling.ts +10 -0
- package/templates/apps/api/src/modules/signal-collectors.ts +10 -0
- package/templates/apps/api/src/modules/workspace.ts +10 -0
- package/templates/apps/api/src/server.ts +117 -1882
- package/templates/apps/api/vercel.json +2 -2
- package/templates/apps/mcp/CLAUDE.md +67 -20
- package/templates/apps/mcp/__tests__/app-entry.test.ts +4 -254
- package/templates/apps/mcp/__tests__/boot-file.test.ts +92 -0
- package/templates/apps/mcp/jest.config.cjs +6 -1
- package/templates/apps/mcp/package.json +5 -13
- package/templates/apps/mcp/src/app.ts +8 -7
- package/templates/apps/mcp/src/index.ts +6 -34
- package/templates/apps/mcp/src/lib/paid-tools.generated.ts +10 -0
- package/templates/apps/mcp/src/lib/topology.generated.ts +2 -2
- package/templates/apps/mcp/src/site.ts +12 -0
- package/templates/apps/web/.env.example +1 -1
- package/templates/apps/web/CLAUDE.md +10 -3
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- package/templates/apps/web/app/[locale]/contact/intake-analytics.ts +1 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/__tests__/magnet-page.test.tsx +22 -1
- package/templates/apps/web/app/[locale]/flows/[slug]/magnet-page.tsx +7 -3
- package/templates/apps/web/app/[locale]/pricing/__tests__/unconnected.test.tsx +43 -0
- package/templates/apps/web/app/[locale]/pricing/page.tsx +7 -3
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/__tests__/route.test.ts +222 -0
- package/templates/apps/web/app/api/offerings/checkout/[lookupKey]/route.ts +10 -3
- package/templates/apps/web/app/api/revalidate/route.ts +3 -3
- package/templates/apps/web/auth.ts +2 -2
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/auth-email.ts +1 -1
- package/templates/apps/web/lib/relay.ts +2 -2
- package/templates/apps/web/lib/release-scope.ts +47 -0
- package/templates/apps/web/lib/server-api.ts +1 -1
- package/templates/apps/web/src/lib/commerce-claim.ts +1 -1
- package/templates/customizations.yaml +37 -0
- package/templates/database/prisma.config.ts +10 -14
- package/templates/database/seed-test.ts +2 -2
- package/templates/database/seed.ts +5 -5
- package/templates/package.json +12 -6
- package/templates/pnpm-workspace.yaml +0 -1
- package/templates/project.yaml +16 -8
- package/templates/tools/jest/reporters.cjs +65 -0
- package/templates/tools/lint-architecture.ts +553 -7
- package/templates/tsconfig.json +1 -2
- package/versions.json +48 -35
- package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +0 -409
- package/templates/apps/api/src/__tests__/factories/agent-caller.ts +0 -102
- package/templates/apps/api/src/__tests__/factories/content-fixture.ts +0 -138
- package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +0 -441
- package/templates/apps/api/src/__tests__/factories/index.ts +0 -70
- package/templates/apps/api/src/__tests__/factories/lead-fixture.ts +0 -82
- package/templates/apps/api/src/__tests__/leads-forwarded-rate-limit.test.ts +0 -135
- package/templates/apps/api/src/__tests__/services/enrichment-shim.test.ts +0 -126
- package/templates/apps/api/src/__tests__/stripe-boot.test.ts +0 -132
- package/templates/apps/api/src/__tests__/support/hub-sign-in-fake-db.ts +0 -362
- package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +0 -184
- package/templates/apps/api/src/bin/abandon-sweep.ts +0 -42
- package/templates/apps/api/src/bin/rate-limit-probe.ts +0 -53
- package/templates/apps/api/src/bin/spokes.ts +0 -198
- package/templates/apps/api/src/bin/stripe-connections-rekey.ts +0 -45
- package/templates/apps/api/src/config/__tests__/hub-require-spoke-key.test.ts +0 -196
- package/templates/apps/api/src/config/__tests__/index.test.ts +0 -233
- package/templates/apps/api/src/config/__tests__/modules.test.ts +0 -76
- package/templates/apps/api/src/config/__tests__/stripe-connection-key.test.ts +0 -185
- package/templates/apps/api/src/config/__tests__/trusted-origins.test.ts +0 -238
- package/templates/apps/api/src/config/index.ts +0 -596
- package/templates/apps/api/src/config/modules.ts +0 -83
- package/templates/apps/api/src/lib/__tests__/agent-store.test.ts +0 -581
- package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +0 -143
- package/templates/apps/api/src/lib/__tests__/consent-ledger-double.ts +0 -237
- package/templates/apps/api/src/lib/__tests__/consent-store.test.ts +0 -353
- package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +0 -201
- package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +0 -224
- package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +0 -120
- package/templates/apps/api/src/lib/__tests__/errors.test.ts +0 -94
- package/templates/apps/api/src/lib/__tests__/file-fallback.test.ts +0 -144
- package/templates/apps/api/src/lib/__tests__/fixtures/HomePage/home.mdx +0 -8
- package/templates/apps/api/src/lib/__tests__/flow-completion-store.test.ts +0 -149
- package/templates/apps/api/src/lib/__tests__/flow-rename-race.db.test.ts +0 -116
- package/templates/apps/api/src/lib/__tests__/hub-sign-in-store.test.ts +0 -209
- package/templates/apps/api/src/lib/__tests__/lead-capture-store.test.ts +0 -257
- package/templates/apps/api/src/lib/__tests__/lead-delivery.test.ts +0 -96
- package/templates/apps/api/src/lib/__tests__/outbound-http.test.ts +0 -125
- package/templates/apps/api/src/lib/__tests__/prisma.test.ts +0 -165
- package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +0 -317
- package/templates/apps/api/src/lib/__tests__/require-paid-tier.test.ts +0 -129
- package/templates/apps/api/src/lib/__tests__/site.test.ts +0 -308
- package/templates/apps/api/src/lib/__tests__/slice-load.test.ts +0 -89
- package/templates/apps/api/src/lib/__tests__/spoke-store.test.ts +0 -202
- package/templates/apps/api/src/lib/__tests__/stripe-admission.test.ts +0 -217
- package/templates/apps/api/src/lib/__tests__/stripe.test.ts +0 -82
- package/templates/apps/api/src/lib/agent-store.ts +0 -613
- package/templates/apps/api/src/lib/auth-email-budget.ts +0 -161
- package/templates/apps/api/src/lib/consent-store.ts +0 -363
- package/templates/apps/api/src/lib/content-adapter.ts +0 -112
- package/templates/apps/api/src/lib/deliverable-asset-store.ts +0 -96
- package/templates/apps/api/src/lib/error-serializer.ts +0 -164
- package/templates/apps/api/src/lib/errors.ts +0 -95
- package/templates/apps/api/src/lib/file-fallback.ts +0 -87
- package/templates/apps/api/src/lib/flow-completion-store.ts +0 -136
- package/templates/apps/api/src/lib/hub-sign-in-store.ts +0 -455
- package/templates/apps/api/src/lib/lead-capture-store.ts +0 -122
- package/templates/apps/api/src/lib/lead-delivery.ts +0 -52
- package/templates/apps/api/src/lib/license-key-store.ts +0 -45
- package/templates/apps/api/src/lib/locales.ts +0 -201
- package/templates/apps/api/src/lib/outbound-http.ts +0 -127
- package/templates/apps/api/src/lib/prisma.ts +0 -21
- package/templates/apps/api/src/lib/proposal-paid-store.ts +0 -66
- package/templates/apps/api/src/lib/rate-limit-probe.ts +0 -165
- package/templates/apps/api/src/lib/rate-limit-store.ts +0 -142
- package/templates/apps/api/src/lib/require-commerce-claim.ts +0 -250
- package/templates/apps/api/src/lib/require-paid-tier.ts +0 -53
- package/templates/apps/api/src/lib/site.ts +0 -257
- package/templates/apps/api/src/lib/slice-load.ts +0 -90
- package/templates/apps/api/src/lib/spoke-store.ts +0 -180
- package/templates/apps/api/src/lib/stripe.ts +0 -321
- package/templates/apps/api/src/lib/webhook-idempotency.ts +0 -156
- package/templates/apps/api/src/middleware/__tests__/adversarial/bearer-token-format.test.ts +0 -111
- package/templates/apps/api/src/middleware/__tests__/adversarial/cookie-or-bearer-precedence.test.ts +0 -172
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-bearer-skip.test.ts +0 -119
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-cookie-path.test.ts +0 -138
- package/templates/apps/api/src/middleware/__tests__/adversarial/csrf-trusted-origins.test.ts +0 -142
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-fixation.test.ts +0 -155
- package/templates/apps/api/src/middleware/__tests__/adversarial/session-timeout.test.ts +0 -139
- package/templates/apps/api/src/middleware/__tests__/auth.bearer-path.test.ts +0 -562
- package/templates/apps/api/src/middleware/__tests__/auth.both-present-precedence.test.ts +0 -76
- package/templates/apps/api/src/middleware/__tests__/auth.cookie-path.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/auth.database-not-configured.test.ts +0 -97
- package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +0 -557
- package/templates/apps/api/src/middleware/__tests__/auth.neither-present.test.ts +0 -72
- package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +0 -140
- package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +0 -721
- package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +0 -220
- package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +0 -430
- package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +0 -1409
- package/templates/apps/api/src/middleware/__tests__/write-budget.test.ts +0 -174
- package/templates/apps/api/src/middleware/auth.ts +0 -864
- package/templates/apps/api/src/middleware/default-tenant.ts +0 -166
- package/templates/apps/api/src/middleware/rate-limit.ts +0 -983
- package/templates/apps/api/src/openapi/__tests__/openapi.test.ts +0 -391
- package/templates/apps/api/src/openapi/__tests__/spec-identity.test.ts +0 -182
- package/templates/apps/api/src/openapi/index.ts +0 -18
- package/templates/apps/api/src/openapi/spec.ts +0 -2148
- package/templates/apps/api/src/openapi/surface-drift.ts +0 -195
- package/templates/apps/api/src/routes/aeo/__tests__/index.test.ts +0 -175
- package/templates/apps/api/src/routes/aeo/index.ts +0 -107
- package/templates/apps/api/src/routes/auth/__tests__/auth-tokens.functional.test.ts +0 -196
- package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +0 -249
- package/templates/apps/api/src/routes/auth/__tests__/hub-sign-in.test.ts +0 -532
- package/templates/apps/api/src/routes/auth/__tests__/tokens.test.ts +0 -313
- package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +0 -413
- package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +0 -609
- package/templates/apps/api/src/routes/auth/hub-sign-in.ts +0 -242
- package/templates/apps/api/src/routes/auth/tokens.ts +0 -211
- package/templates/apps/api/src/routes/auth/transactional-email.ts +0 -301
- package/templates/apps/api/src/routes/auth/user.ts +0 -305
- package/templates/apps/api/src/routes/billing/plan-checkout.ts +0 -332
- package/templates/apps/api/src/routes/checkout/__tests__/live-key.test.ts +0 -178
- package/templates/apps/api/src/routes/checkout/__tests__/offerings-authorization.test.ts +0 -1426
- package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +0 -448
- package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +0 -1742
- package/templates/apps/api/src/routes/checkout/index.ts +0 -34
- package/templates/apps/api/src/routes/checkout/session.ts +0 -171
- package/templates/apps/api/src/routes/checkout/sessions.ts +0 -540
- package/templates/apps/api/src/routes/consent/__tests__/account.test.ts +0 -386
- package/templates/apps/api/src/routes/consent/__tests__/sign-up-rate-limit.test.ts +0 -160
- package/templates/apps/api/src/routes/consent/account.ts +0 -268
- package/templates/apps/api/src/routes/consent/cookie.ts +0 -90
- package/templates/apps/api/src/routes/consent/index.ts +0 -26
- package/templates/apps/api/src/routes/consent/unsubscribe.ts +0 -127
- package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +0 -853
- package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +0 -230
- package/templates/apps/api/src/routes/content/__tests__/list-types.test.ts +0 -44
- package/templates/apps/api/src/routes/content/__tests__/locale.test.ts +0 -118
- package/templates/apps/api/src/routes/content/__tests__/offerings.test.ts +0 -731
- package/templates/apps/api/src/routes/content/__tests__/pricing.test.ts +0 -753
- package/templates/apps/api/src/routes/content/__tests__/rate-limit.test.ts +0 -51
- package/templates/apps/api/src/routes/content/__tests__/search.test.ts +0 -450
- package/templates/apps/api/src/routes/content/__tests__/shown-offerings.test.ts +0 -762
- package/templates/apps/api/src/routes/content/get-page.ts +0 -183
- package/templates/apps/api/src/routes/content/index.ts +0 -49
- package/templates/apps/api/src/routes/content/list-pages.ts +0 -74
- package/templates/apps/api/src/routes/content/list-types.ts +0 -19
- package/templates/apps/api/src/routes/content/offerings.ts +0 -184
- package/templates/apps/api/src/routes/content/pricing.ts +0 -176
- package/templates/apps/api/src/routes/content/rate-limit.ts +0 -22
- package/templates/apps/api/src/routes/content/search.ts +0 -100
- package/templates/apps/api/src/routes/content/shown-offerings.ts +0 -229
- package/templates/apps/api/src/routes/leads/__tests__/capture.test.ts +0 -88
- package/templates/apps/api/src/routes/leads/__tests__/list.test.ts +0 -171
- package/templates/apps/api/src/routes/leads/__tests__/magnet-completion.test.ts +0 -515
- package/templates/apps/api/src/routes/leads/__tests__/spoke.test.ts +0 -392
- package/templates/apps/api/src/routes/leads/__tests__/track.test.ts +0 -165
- package/templates/apps/api/src/routes/leads/index.ts +0 -639
- package/templates/apps/api/src/routes/leads/list.ts +0 -104
- package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +0 -626
- package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +0 -1268
- package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +0 -847
- package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +0 -491
- package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +0 -476
- package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +0 -872
- package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +0 -1022
- package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +0 -484
- package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +0 -535
- package/templates/apps/api/src/routes/project-listings/index.ts +0 -164
- package/templates/apps/api/src/routes/project-listings/me.ts +0 -87
- package/templates/apps/api/src/routes/project-listings/patch-copy.ts +0 -224
- package/templates/apps/api/src/routes/project-listings/patch-draft.ts +0 -102
- package/templates/apps/api/src/routes/project-listings/public.ts +0 -98
- package/templates/apps/api/src/routes/project-listings/respond.ts +0 -48
- package/templates/apps/api/src/routes/project-listings/resume-token.ts +0 -27
- package/templates/apps/api/src/routes/project-listings/start.ts +0 -140
- package/templates/apps/api/src/routes/project-listings/submit.ts +0 -130
- package/templates/apps/api/src/routes/project-listings/verify-email.ts +0 -150
- package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +0 -686
- package/templates/apps/api/src/routes/requests/confirm.ts +0 -601
- package/templates/apps/api/src/routes/requests/index.ts +0 -54
- package/templates/apps/api/src/routes/test/auth/__tests__/session.test.ts +0 -306
- package/templates/apps/api/src/routes/test/auth/session.ts +0 -143
- package/templates/apps/api/src/routes/webhooks/README.md +0 -398
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-checkout-consent.test.ts +0 -649
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +0 -749
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +0 -449
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +0 -264
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode-live.test.ts +0 -159
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-livemode.test.ts +0 -158
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-offerings.test.ts +0 -814
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +0 -369
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +0 -215
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +0 -301
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +0 -809
- package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +0 -1155
- package/templates/apps/api/src/routes/webhooks/index.ts +0 -141
- package/templates/apps/api/src/routes/webhooks/stripe-offerings.ts +0 -384
- package/templates/apps/api/src/routes/webhooks/stripe.ts +0 -2028
- package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +0 -645
- package/templates/apps/api/src/services/__tests__/answer-distributions.test.ts +0 -132
- package/templates/apps/api/src/services/__tests__/audit-log.test.ts +0 -1028
- package/templates/apps/api/src/services/__tests__/checkout-plan.test.ts +0 -313
- package/templates/apps/api/src/services/__tests__/consent-ledger.test.ts +0 -503
- package/templates/apps/api/src/services/__tests__/consent-migration.test.ts +0 -65
- package/templates/apps/api/src/services/__tests__/consent.test.ts +0 -299
- package/templates/apps/api/src/services/__tests__/default-tenant.test.ts +0 -147
- package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +0 -877
- package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +0 -379
- package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +0 -368
- package/templates/apps/api/src/services/__tests__/entitlements.test.ts +0 -142
- package/templates/apps/api/src/services/__tests__/hub-sign-in.test.ts +0 -854
- package/templates/apps/api/src/services/__tests__/keyless-workspace-predicate.test.ts +0 -234
- package/templates/apps/api/src/services/__tests__/lead-accept-user.test.ts +0 -251
- package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +0 -2660
- package/templates/apps/api/src/services/__tests__/listing-config.test.ts +0 -166
- package/templates/apps/api/src/services/__tests__/magnet-completion.test.ts +0 -389
- package/templates/apps/api/src/services/__tests__/person.test.ts +0 -1204
- package/templates/apps/api/src/services/__tests__/plan-offerings.test.ts +0 -450
- package/templates/apps/api/src/services/__tests__/project-listings.counts.test.ts +0 -202
- package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +0 -151
- package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +0 -137
- package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +0 -531
- package/templates/apps/api/src/services/__tests__/revalidation.test.ts +0 -372
- package/templates/apps/api/src/services/__tests__/slack-notify.test.ts +0 -348
- package/templates/apps/api/src/services/__tests__/spoke-resolution.test.ts +0 -660
- package/templates/apps/api/src/services/__tests__/usage-aggregation.test.ts +0 -941
- package/templates/apps/api/src/services/__tests__/usage-credits.test.ts +0 -588
- package/templates/apps/api/src/services/__tests__/verified-email.test.ts +0 -78
- package/templates/apps/api/src/services/abandon-email.ts +0 -336
- package/templates/apps/api/src/services/aeo-score.ts +0 -325
- package/templates/apps/api/src/services/answer-distributions.ts +0 -138
- package/templates/apps/api/src/services/audit-log.ts +0 -961
- package/templates/apps/api/src/services/checkout-buyer.ts +0 -168
- package/templates/apps/api/src/services/consent.ts +0 -834
- package/templates/apps/api/src/services/default-tenant.ts +0 -416
- package/templates/apps/api/src/services/deliverable-fulfillment.ts +0 -750
- package/templates/apps/api/src/services/dunning-policy.ts +0 -294
- package/templates/apps/api/src/services/enrichment-shim.ts +0 -53
- package/templates/apps/api/src/services/entitlements.ts +0 -338
- package/templates/apps/api/src/services/hub-sign-in.ts +0 -472
- package/templates/apps/api/src/services/lead-accept-user.ts +0 -126
- package/templates/apps/api/src/services/lead-promotion.ts +0 -160
- package/templates/apps/api/src/services/lead-routing.ts +0 -1372
- package/templates/apps/api/src/services/leads-inbox.ts +0 -312
- package/templates/apps/api/src/services/listing-config.ts +0 -178
- package/templates/apps/api/src/services/magnet-completion.ts +0 -242
- package/templates/apps/api/src/services/offerings/__tests__/catalog.test.ts +0 -348
- package/templates/apps/api/src/services/offerings/__tests__/checkout-session-record.test.ts +0 -268
- package/templates/apps/api/src/services/offerings/__tests__/connection.test.ts +0 -975
- package/templates/apps/api/src/services/offerings/__tests__/fixtures.ts +0 -416
- package/templates/apps/api/src/services/offerings/__tests__/org-products.test.ts +0 -400
- package/templates/apps/api/src/services/offerings/__tests__/readers.test.ts +0 -685
- package/templates/apps/api/src/services/offerings/__tests__/source.test.ts +0 -231
- package/templates/apps/api/src/services/offerings/catalog.ts +0 -318
- package/templates/apps/api/src/services/offerings/checkout-authorization.ts +0 -403
- package/templates/apps/api/src/services/offerings/checkout-session-record.ts +0 -192
- package/templates/apps/api/src/services/offerings/connection.ts +0 -1083
- package/templates/apps/api/src/services/offerings/index.ts +0 -614
- package/templates/apps/api/src/services/offerings/source.ts +0 -140
- package/templates/apps/api/src/services/offerings/store.ts +0 -150
- package/templates/apps/api/src/services/owner-workspaces.ts +0 -132
- package/templates/apps/api/src/services/person.ts +0 -1211
- package/templates/apps/api/src/services/plan-offerings.ts +0 -125
- package/templates/apps/api/src/services/project-listing-resume-email.ts +0 -326
- package/templates/apps/api/src/services/project-listings.ts +0 -2085
- package/templates/apps/api/src/services/public-site-resolver.ts +0 -396
- package/templates/apps/api/src/services/request-confirm.ts +0 -698
- package/templates/apps/api/src/services/revalidation.ts +0 -235
- package/templates/apps/api/src/services/slack-notify.ts +0 -291
- package/templates/apps/api/src/services/usage-aggregation.ts +0 -516
- package/templates/apps/api/src/services/usage-credits.ts +0 -340
- package/templates/apps/api/src/services/verified-email.ts +0 -71
- package/templates/apps/mcp/__tests__/abuse/daily-cap.test.ts +0 -52
- package/templates/apps/mcp/__tests__/abuse/email-validator.test.ts +0 -46
- package/templates/apps/mcp/__tests__/abuse/guard.test.ts +0 -198
- package/templates/apps/mcp/__tests__/abuse/honeypot.test.ts +0 -36
- package/templates/apps/mcp/__tests__/abuse/user-agent-deny.test.ts +0 -54
- package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +0 -116
- package/templates/apps/mcp/__tests__/audit-single-page.test.ts +0 -299
- package/templates/apps/mcp/__tests__/boot.test.ts +0 -280
- package/templates/apps/mcp/__tests__/catalog-drift.test.ts +0 -359
- package/templates/apps/mcp/__tests__/config/modules.test.ts +0 -78
- package/templates/apps/mcp/__tests__/get_business_hours.test.ts +0 -82
- package/templates/apps/mcp/__tests__/get_faq.test.ts +0 -80
- package/templates/apps/mcp/__tests__/get_locations.test.ts +0 -65
- package/templates/apps/mcp/__tests__/get_offerings.test.ts +0 -557
- package/templates/apps/mcp/__tests__/get_pricing.test.ts +0 -524
- package/templates/apps/mcp/__tests__/get_site_info.test.ts +0 -81
- package/templates/apps/mcp/__tests__/http-transport.test.ts +0 -1232
- package/templates/apps/mcp/__tests__/index.test.ts +0 -195
- package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +0 -191
- package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +0 -531
- package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +0 -70
- package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +0 -162
- package/templates/apps/mcp/__tests__/lib/content-root.test.ts +0 -93
- package/templates/apps/mcp/__tests__/lib/errors.test.ts +0 -75
- package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +0 -180
- package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +0 -124
- package/templates/apps/mcp/__tests__/list_pages.test.ts +0 -268
- package/templates/apps/mcp/__tests__/locale.test.ts +0 -120
- package/templates/apps/mcp/__tests__/module-exclusion.test.ts +0 -175
- package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +0 -101
- package/templates/apps/mcp/__tests__/rate-limit-write.test.ts +0 -189
- package/templates/apps/mcp/__tests__/read_content.test.ts +0 -511
- package/templates/apps/mcp/__tests__/request_callback.test.ts +0 -160
- package/templates/apps/mcp/__tests__/search_content.test.ts +0 -271
- package/templates/apps/mcp/__tests__/server.test.ts +0 -388
- package/templates/apps/mcp/__tests__/start_purchase.test.ts +0 -448
- package/templates/apps/mcp/__tests__/submit_lead.test.ts +0 -222
- package/templates/apps/mcp/__tests__/subscribe_newsletter.test.ts +0 -152
- package/templates/apps/mcp/__tests__/tools/create_project.test.ts +0 -243
- package/templates/apps/mcp/__tests__/tools/purchase.test.ts +0 -451
- package/templates/apps/mcp/src/abuse/daily-cap.ts +0 -47
- package/templates/apps/mcp/src/abuse/email-validator.ts +0 -25
- package/templates/apps/mcp/src/abuse/honeypot.ts +0 -21
- package/templates/apps/mcp/src/abuse/index.ts +0 -349
- package/templates/apps/mcp/src/abuse/user-agent-deny.ts +0 -58
- package/templates/apps/mcp/src/boot.ts +0 -167
- package/templates/apps/mcp/src/config/modules.ts +0 -43
- package/templates/apps/mcp/src/http-transport.ts +0 -564
- package/templates/apps/mcp/src/lib/audit-single-page.ts +0 -308
- package/templates/apps/mcp/src/lib/commerce-claim.ts +0 -263
- package/templates/apps/mcp/src/lib/content-adapter.ts +0 -116
- package/templates/apps/mcp/src/lib/empty-content-adapter.ts +0 -140
- package/templates/apps/mcp/src/lib/errors.ts +0 -61
- package/templates/apps/mcp/src/lib/license-key-store.ts +0 -45
- package/templates/apps/mcp/src/lib/locales.ts +0 -171
- package/templates/apps/mcp/src/lib/prisma.ts +0 -39
- package/templates/apps/mcp/src/lib/public-workspace.ts +0 -133
- package/templates/apps/mcp/src/lib/resolve-locale.ts +0 -30
- package/templates/apps/mcp/src/lib/shown-offerings.ts +0 -105
- package/templates/apps/mcp/src/lib/site-config.ts +0 -53
- package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +0 -59
- package/templates/apps/mcp/src/request-context.ts +0 -52
- package/templates/apps/mcp/src/server.ts +0 -343
- package/templates/apps/mcp/src/serverless-app.ts +0 -88
- package/templates/apps/mcp/src/tools/audit.ts +0 -127
- package/templates/apps/mcp/src/tools/capture_lead.ts +0 -66
- package/templates/apps/mcp/src/tools/create_project.ts +0 -134
- package/templates/apps/mcp/src/tools/get_business_hours.ts +0 -68
- package/templates/apps/mcp/src/tools/get_faq.ts +0 -71
- package/templates/apps/mcp/src/tools/get_locations.ts +0 -88
- package/templates/apps/mcp/src/tools/get_offerings.ts +0 -96
- package/templates/apps/mcp/src/tools/get_pricing.ts +0 -94
- package/templates/apps/mcp/src/tools/get_site_info.ts +0 -86
- package/templates/apps/mcp/src/tools/index.ts +0 -138
- package/templates/apps/mcp/src/tools/list_pages.ts +0 -68
- package/templates/apps/mcp/src/tools/person_notes.ts +0 -25
- package/templates/apps/mcp/src/tools/proposals.ts +0 -27
- package/templates/apps/mcp/src/tools/purchase.ts +0 -205
- package/templates/apps/mcp/src/tools/read_content.ts +0 -81
- package/templates/apps/mcp/src/tools/request_callback.ts +0 -52
- package/templates/apps/mcp/src/tools/search_content.ts +0 -63
- package/templates/apps/mcp/src/tools/subscribe_newsletter.ts +0 -54
- package/templates/apps/mcp/src/workspace-server.ts +0 -224
- package/templates/database/CHANGELOG.md +0 -981
- package/templates/database/LICENSE +0 -202
- package/templates/database/NOTICE +0 -2
- package/templates/database/README.md +0 -243
- package/templates/database/__tests__/agents.db.test.ts +0 -320
- package/templates/database/__tests__/appointment.db.test.ts +0 -106
- package/templates/database/__tests__/artifact-content-store.db.test.ts +0 -316
- package/templates/database/__tests__/composite-fence.db.test.ts +0 -206
- package/templates/database/__tests__/consent-ledger.db.test.ts +0 -345
- package/templates/database/__tests__/consent-source-checkout-migration.test.ts +0 -79
- package/templates/database/__tests__/fence-fan-out.db.test.ts +0 -715
- package/templates/database/__tests__/fixtures/appointment-create-probe.ts +0 -79
- package/templates/database/__tests__/fixtures/person-backfill.json +0 -264
- package/templates/database/__tests__/fixtures/person-contact-backfill.json +0 -182
- package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +0 -100
- package/templates/database/__tests__/flow-completion-migration.test.ts +0 -115
- package/templates/database/__tests__/flow-completion.db.test.ts +0 -136
- package/templates/database/__tests__/flow-workspace-key.db.test.ts +0 -263
- package/templates/database/__tests__/flows-listing-diagnostic.test.ts +0 -392
- package/templates/database/__tests__/flows-presets.test.ts +0 -173
- package/templates/database/__tests__/in-page-magnets-migration.test.ts +0 -161
- package/templates/database/__tests__/lead-idempotency-key.db.test.ts +0 -92
- package/templates/database/__tests__/member-area.db.test.ts +0 -257
- package/templates/database/__tests__/member-contract-migration.test.ts +0 -85
- package/templates/database/__tests__/member-contract.db.test.ts +0 -413
- package/templates/database/__tests__/offerings-checkout-session.db.test.ts +0 -270
- package/templates/database/__tests__/offerings-migration.test.ts +0 -197
- package/templates/database/__tests__/offerings-shown-price-ids-migration.test.ts +0 -86
- package/templates/database/__tests__/offerings.db.test.ts +0 -303
- package/templates/database/__tests__/outbound-message-action.db.test.ts +0 -80
- package/templates/database/__tests__/person-contact.db.test.ts +0 -563
- package/templates/database/__tests__/person-notes.db.test.ts +0 -249
- package/templates/database/__tests__/person.db.test.ts +0 -586
- package/templates/database/__tests__/piece-kind-migration.test.ts +0 -67
- package/templates/database/__tests__/piece-kind.db.test.ts +0 -208
- package/templates/database/__tests__/prefixed-ids.db.test.ts +0 -222
- package/templates/database/__tests__/project-listing-consent-at.db.test.ts +0 -111
- package/templates/database/__tests__/seed.test.ts +0 -272
- package/templates/database/__tests__/spoke-registry.db.test.ts +0 -191
- package/templates/database/__tests__/tenancy.test.ts +0 -141
- package/templates/database/__tests__/trial-magnet-migration.test.ts +0 -186
- package/templates/database/__tests__/user-cascade.test.ts +0 -140
- package/templates/database/_gitignore +0 -8
- package/templates/database/auth/.gitkeep +0 -0
- package/templates/database/auth/schema.prisma +0 -641
- package/templates/database/config/.gitkeep +0 -0
- package/templates/database/config/schema.prisma +0 -441
- package/templates/database/content/.gitkeep +0 -0
- package/templates/database/content/schema.prisma +0 -339
- package/templates/database/eslint.config.mjs +0 -69
- package/templates/database/flows/listing-diagnostic.ts +0 -182
- package/templates/database/flows/presets.ts +0 -315
- package/templates/database/inbox/.gitkeep +0 -0
- package/templates/database/inbox/README.md +0 -3
- package/templates/database/inbox/__tests__/schema.test.ts +0 -44
- package/templates/database/inbox/schema.prisma +0 -1447
- package/templates/database/jest.config.cjs +0 -36
- package/templates/database/migrations/20260508000000_add_inbox_namespace/migration.sql +0 -328
- package/templates/database/migrations/20260513000000_better_auth_migration/migration.sql +0 -100
- package/templates/database/migrations/20260515000000_add_user_billing_fields/migration.sql +0 -28
- package/templates/database/migrations/20260516000000_add_user_tier_care_plan_seat/migration.sql +0 -25
- package/templates/database/migrations/20260518000000_add_telemetry_records/migration.sql +0 -42
- package/templates/database/migrations/20260525000000_theme_wiring/migration.sql +0 -67
- package/templates/database/migrations/20260710000000_retire_commercial_tier/migration.sql +0 -21
- package/templates/database/migrations/20260712215647_add_multi_tenant_tenancy/migration.sql +0 -201
- package/templates/database/migrations/20260713143320_reanchor_site_config_to_workspace/migration.sql +0 -67
- package/templates/database/migrations/20260713174000_add_audit_logs/migration.sql +0 -46
- package/templates/database/migrations/20260713190000_drop_telemetry_records/migration.sql +0 -25
- package/templates/database/migrations/20260713192000_add_uuidv7_function/migration.sql +0 -49
- package/templates/database/migrations/20260713192429_prefixed_uuid_entity_ids/migration.sql +0 -197
- package/templates/database/migrations/20260713200000_add_org_billing/migration.sql +0 -32
- package/templates/database/migrations/20260714000000_add_lead_promotion_fields/migration.sql +0 -22
- package/templates/database/migrations/20260714010000_add_usage_billing_content_models/migration.sql +0 -151
- package/templates/database/migrations/20260714020000_add_usage_billing_auth_config_models/migration.sql +0 -223
- package/templates/database/migrations/20260714030000_credit_balance_non_negative/migration.sql +0 -22
- package/templates/database/migrations/20260714030000_widen_usage_billing_report_aggregates/migration.sql +0 -32
- package/templates/database/migrations/20260810233516_add_flow_engine_models/migration.sql +0 -40
- package/templates/database/migrations/20260811020000_add_flow_session_abandon_email_columns/migration.sql +0 -4
- package/templates/database/migrations/20260811030000_add_flow_session_abandon_email_index/migration.sql +0 -2
- package/templates/database/migrations/20260811040000_add_flow_session_segment/migration.sql +0 -2
- package/templates/database/migrations/20260811050000_add_deliverable_models/migration.sql +0 -29
- package/templates/database/migrations/20260812000000_add_deliverable_grant_send_columns/migration.sql +0 -6
- package/templates/database/migrations/20260902222948_add_waitlist_experiment_models/migration.sql +0 -39
- package/templates/database/migrations/20260902224500_add_waitlist_id_format_checks/migration.sql +0 -24
- package/templates/database/migrations/20260903004112_add_flow_session_flags_aeo_score/migration.sql +0 -3
- package/templates/database/migrations/20260903010000_add_playbook_instance/migration.sql +0 -33
- package/templates/database/migrations/20260904000000_add_waitlist_followup_send/migration.sql +0 -30
- package/templates/database/migrations/20260905230000_add_flow_checkout/migration.sql +0 -47
- package/templates/database/migrations/20260906000000_add_flow_checkout_idempotency/migration.sql +0 -16
- package/templates/database/migrations/20260907120000_add_project_listing/migration.sql +0 -47
- package/templates/database/migrations/20260907130000_add_project_listing_slack_columns/migration.sql +0 -10
- package/templates/database/migrations/20260907180000_add_listing_csv_send/migration.sql +0 -26
- package/templates/database/migrations/20260909120000_project_listings_platform/migration.sql +0 -90
- package/templates/database/migrations/20260909180000_listing_draft_and_fields/migration.sql +0 -174
- package/templates/database/migrations/20260910120000_listing_public_site_key/migration.sql +0 -14
- package/templates/database/migrations/20260911120000_listing_copy_edit_audit/migration.sql +0 -25
- package/templates/database/migrations/20260911140000_listing_structured_address/migration.sql +0 -32
- package/templates/database/migrations/20260911180000_consent_grants/migration.sql +0 -71
- package/templates/database/migrations/20260911200000_listing_site_answers/migration.sql +0 -30
- package/templates/database/migrations/20260912120000_listing_owner_link/migration.sql +0 -49
- package/templates/database/migrations/20260914120000_listing_founder_identity/migration.sql +0 -123
- package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +0 -15
- package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +0 -158
- package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +0 -40
- package/templates/database/migrations/20260918120000_add_appointment/migration.sql +0 -67
- package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +0 -70
- package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +0 -181
- package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +0 -172
- package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +0 -41
- package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +0 -185
- package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +0 -70
- package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +0 -57
- package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +0 -68
- package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +0 -1067
- package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +0 -210
- package/templates/database/migrations/20261003120000_spoke_registry/migration.sql +0 -80
- package/templates/database/migrations/20261003130000_scheduling_connection/migration.sql +0 -49
- package/templates/database/migrations/20261005120000_agents/migration.sql +0 -84
- package/templates/database/migrations/20261008120000_user_last_workspace/migration.sql +0 -35
- package/templates/database/migrations/20261008130000_lead_idempotency_key/migration.sql +0 -20
- package/templates/database/migrations/20261009120000_agent_grants/migration.sql +0 -33
- package/templates/database/migrations/20261010120000_person/migration.sql +0 -106
- package/templates/database/migrations/20261010121000_person_backfill/migration.sql +0 -132
- package/templates/database/migrations/20261010130000_agent_grants_people_read/migration.sql +0 -20
- package/templates/database/migrations/20261011120000_member_area/migration.sql +0 -158
- package/templates/database/migrations/20261011130000_agent_grants_member_pieces_manage/migration.sql +0 -21
- package/templates/database/migrations/20261012120000_member_contract/migration.sql +0 -192
- package/templates/database/migrations/20261013120000_lead_spoke_checkout/migration.sql +0 -20
- package/templates/database/migrations/20261014120000_consent_ledger/migration.sql +0 -122
- package/templates/database/migrations/20261014120000_person_contact/migration.sql +0 -231
- package/templates/database/migrations/20261015120000_person_notes/migration.sql +0 -77
- package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +0 -43
- package/templates/database/migrations/20261016120000_piece_kind/migration.sql +0 -95
- package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +0 -30
- package/templates/database/migrations/20261018120000_flow_completion/migration.sql +0 -52
- package/templates/database/migrations/20261019120000_consent_source_checkout/migration.sql +0 -27
- package/templates/database/migrations/20261020120000_offerings_data_model/migration.sql +0 -146
- package/templates/database/migrations/20261021120000_offerings_checkout_session/migration.sql +0 -77
- package/templates/database/migrations/20261022120000_in_page_magnets/migration.sql +0 -45
- package/templates/database/migrations/20261023120000_offerings_shown_price_ids/migration.sql +0 -47
- package/templates/database/migrations/20261024120000_organization_plan_checkout_session/migration.sql +0 -16
- package/templates/database/migrations/20261025120000_trial_magnet/migration.sql +0 -28
- package/templates/database/migrations/20261026120000_trial_magnet_proof_line/migration.sql +0 -23
- package/templates/database/migrations/migration_lock.toml +0 -3
- package/templates/database/ops/.gitkeep +0 -0
- package/templates/database/ops/schema.prisma +0 -43
- package/templates/database/package.json +0 -89
- package/templates/database/schema.prisma +0 -71
- package/templates/database/scripts/db-generate-locked.sh +0 -80
- package/templates/database/scripts/person-backfill.sql +0 -132
- package/templates/database/tenancy.ts +0 -183
- package/templates/database/tsconfig.build.json +0 -16
- package/templates/database/tsconfig.flows.json +0 -15
- package/templates/database/tsconfig.json +0 -16
- package/templates/database/tsconfig.tenancy.json +0 -14
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 2,
|
|
3
|
-
"ignoreCommand": "[ -n \"$VERCEL_GIT_PREVIOUS_SHA\" ] && cd ../.. && git diff --quiet \"$VERCEL_GIT_PREVIOUS_SHA\" HEAD -- apps/api packages database pnpm-lock.yaml package.json pnpm-workspace.yaml turbo.json 'tsconfig*.json' || exit 1",
|
|
4
|
-
"buildCommand": "cd ../.. && pnpm run --filter @working-theory/api build:vercel",
|
|
3
|
+
"ignoreCommand": "[ -n \"$VERCEL_GIT_PREVIOUS_SHA\" ] && cd ../.. && git diff --quiet \"$VERCEL_GIT_PREVIOUS_SHA\" HEAD -- apps/api packages packages-paid database pnpm-lock.yaml package.json pnpm-workspace.yaml turbo.json 'tsconfig*.json' || exit 1",
|
|
4
|
+
"buildCommand": "cd ../.. && pnpm run --filter @working-theory/app-api build:vercel",
|
|
5
5
|
"installCommand": "cd ../.. && pnpm install --frozen-lockfile",
|
|
6
6
|
"outputDirectory": "public",
|
|
7
7
|
"framework": null,
|
|
@@ -8,10 +8,37 @@ Inherits root `CLAUDE.md`. This file adds MCP-specific rules.
|
|
|
8
8
|
- Transport: stdio at launch
|
|
9
9
|
- Discovery: `/.well-known/mcp.json` published from `apps/web`
|
|
10
10
|
|
|
11
|
+
## The server is a package; this app is a boot set (#9460)
|
|
12
|
+
|
|
13
|
+
The server — the transports, the boot sequence, the abuse guard and the 15 free tools — is
|
|
14
|
+
`@working-theory/mcp-server` (`packages/mcp-server`), with two entry points: `.` and `./hub`.
|
|
15
|
+
Each paid module's tools ride that module's own package (`packages-paid/mcp-scheduling`,
|
|
16
|
+
`mcp-signal-collectors`, `mcp-workspace`), which base code reaches only through the generated
|
|
17
|
+
registry below. A version bump of those packages is the whole of taking an MCP change.
|
|
18
|
+
|
|
19
|
+
`src/` holds exactly five files, and nothing else may be added to it (`__tests__/boot-file.test.ts`
|
|
20
|
+
ships to every scaffold and fails on any other import):
|
|
21
|
+
|
|
22
|
+
- **`index.ts`** and **`app.ts`** — the two deployment entries (next section).
|
|
23
|
+
- **`site.ts`** — builds the `McpSite` the package runs for: `{ topology, paidToolPacks }`.
|
|
24
|
+
- **`lib/topology.generated.ts`** — the topology seam create-ailk renders (hub or spoke).
|
|
25
|
+
- **`lib/paid-tools.generated.ts`** — the paid MCP packs this site carries, one bundled
|
|
26
|
+
`import()` each, rendered by create-ailk from `MODULE_SLICES` (`paidMcpToolPackages`) and
|
|
27
|
+
`apps/mcp/package.json`; `// oss: false` on line 1 exactly when a pack is present. The
|
|
28
|
+
monorepo copy carries all three. A module-gated or signed-in tool resolves from the union of
|
|
29
|
+
the loaded packs at call time; a registered tool whose pack a site does not carry answers the
|
|
30
|
+
tool error `MCP slice drift: no installed package serves '<name>'`.
|
|
31
|
+
|
|
32
|
+
The suites that stay here are the composition root's: `api-parity`, `pro-tool-call-gate`,
|
|
33
|
+
`workspace-surface`, `write-tool-guard` and `create-booking-guard` (they call paid handlers through
|
|
34
|
+
the real `site.ts`), `app-entry` (the Vercel entry's source text) and `boot-file`. Everything else
|
|
35
|
+
runs in the package. Paths in the sections below that name `src/<file>` other than the five above
|
|
36
|
+
now mean `packages/mcp-server/src/<file>`.
|
|
37
|
+
|
|
11
38
|
## Two entrypoints, one boot (#8070)
|
|
12
39
|
|
|
13
40
|
- **`src/index.ts`** — run locally: stdio (the default), or HTTP on `MCP_HTTP_PORT` with
|
|
14
|
-
`MCP_TRANSPORT=http`.
|
|
41
|
+
`MCP_TRANSPORT=http`. It is `await runMcp(site)`; the transport branch is the package's `run.ts`.
|
|
15
42
|
- **`src/app.ts`** — the Vercel entry. A Vercel project whose root directory is `apps/mcp`
|
|
16
43
|
detects it (it imports Fastify) and calls its default export, `serverlessHandler(app)`: a
|
|
17
44
|
`(req, res)` function, the shape Vercel's Node runtime runs — a bare Fastify instance is not
|
|
@@ -22,18 +49,30 @@ Inherits root `CLAUDE.md`. This file adds MCP-specific rules.
|
|
|
22
49
|
reads it by static analysis). `tsconfig.json` names `module` and `moduleResolution` itself:
|
|
23
50
|
Vercel's type-check edits the entry's nearest `tsconfig.json` as raw JSON before `extends`,
|
|
24
51
|
and without its own `module` it switches `strict` off, which fails 11 narrowing sites.
|
|
25
|
-
- Both call `bootMcp()`
|
|
26
|
-
configuration through `httpTransportConfigFromEnv()`
|
|
27
|
-
never to one entry. `src/app.ts` stays thin; what a test needs
|
|
52
|
+
- Both call the package's `bootMcp(site)` before building a transport, and the package reads the
|
|
53
|
+
HTTP configuration through `httpTransportConfigFromEnv()` (`packages/mcp-server/src/boot.ts`).
|
|
54
|
+
Add a boot step to `bootMcp()`, never to one entry. `src/app.ts` stays thin; what a test needs
|
|
55
|
+
is in the package's `serverless-app.ts`.
|
|
28
56
|
- **`MCP_HTTP_STATELESS`** picks the transport mode: `true`/`1` stateless (no sessions; any
|
|
29
57
|
instance answers), `false`/`0` stateful (sessions in one process's memory). Unset, the
|
|
30
58
|
Vercel entry is stateless and `src/index.ts` is stateful. Any other value fails the boot.
|
|
31
59
|
The Vercel entry needs stateless: a session kept in one instance is lost on the next.
|
|
32
60
|
- **Content root.** Every content tool and `audit` take their root from `mcpContentRoot()`
|
|
33
61
|
(`lib/content-adapter.ts`): `AILK_CONTENT_ROOT`, else `<cwd>/content`, else
|
|
34
|
-
`<cwd>/../../content`. Never build a content path from `process.cwd()` in a tool
|
|
62
|
+
`<cwd>/../../content`. Never build a content path from `process.cwd()` in a tool — the one
|
|
63
|
+
standing exception is `create_project`, whose `resolveCliBin()` has always spawned
|
|
64
|
+
`<cwd>/packages/create-ailk/dist/cli.js`; its release-scope read shares that root (next).
|
|
35
65
|
- **`create_project`** is not served on a spoke: the generated seam's `UNSERVED_MCP_TOOLS`
|
|
36
|
-
keeps it out of registration, and the web manifest drops the same list.
|
|
66
|
+
keeps it out of registration, and the web manifest drops the same list. It is also not
|
|
67
|
+
served while the Free level is held (#9534): it spawns a keyless scaffold, so
|
|
68
|
+
`isFreeLevelReleased()` (`tools/create_project.ts`) registers it only when
|
|
69
|
+
`<cwd>/packages/create-ailk/release-scope.json` marks `levels.free` released, and re-applies
|
|
70
|
+
that at call time. The contract that implies: the tool exists only in a monorepo checkout
|
|
71
|
+
started from the repo root — anywhere else the file is absent and so is the tool, where it
|
|
72
|
+
could not run anyway (no `dist/cli.js`). The scope FILE alone decides — a release-scope
|
|
73
|
+
decision, never a licence check, and the CLI's `AILK_RELEASE_SCOPE=ignore` bypass is not
|
|
74
|
+
honoured; a missing or unreadable file fails closed with one stderr line. apps/web's
|
|
75
|
+
`/.well-known/mcp.json` drops it on the same read (`apps/web/lib/release-scope.ts`).
|
|
37
76
|
|
|
38
77
|
### What a spoke's MCP host on Vercel enforces
|
|
39
78
|
|
|
@@ -81,21 +120,24 @@ Every tool maps 1:1 to an `apps/api` endpoint. When you change a tool, change th
|
|
|
81
120
|
**Flow (2):** `get_flow`, `submit_flow_step` — module-gated (`module: "signal-collectors"`, D-48, #5366) and licence-feature-tagged (`feature: "flows-deliverables"`, #7136): identity-blind like every tool in this list, registered only when the signal-collectors module is present, and gated on the deployment's `flows-deliverables` licence feature under `MCP_FEATURE_GATE_MODE`, the same shape Booking below has. `submit_flow_step` takes the HTTP write branch (its own daily cap, `MCP_ABUSE_SUBMIT_FLOW_STEP_DAILY_CAP`, default 50 — #8071)
|
|
82
121
|
**Booking (4):** `list_availability`, `get_event_meta`, `list_meetings`, `create_booking` — module-gated (`module: "scheduling"`) and licence-feature-tagged (`feature: "scheduling"`, #7136), gated on the deployment's `scheduling` licence feature under `MCP_FEATURE_GATE_MODE`. `create_booking` takes the HTTP write branch (its own daily cap, `MCP_ABUSE_CREATE_BOOKING_DAILY_CAP`, default 20, and an `attendee.email` format check — #8071). `list_meetings` (#8843 D5) twins `GET /v1/schedule/meetings`: it takes no argument and returns the site's Live meetings — slug, visibility, position and whether each can be booked, plus a bookable one's calLink, title, length, description and price; `private` means unlisted, not secret
|
|
83
122
|
|
|
84
|
-
### Why the parity test counts 21 and a keyless server registers 20
|
|
123
|
+
### Why the parity test counts 21 and a keyless server registers 19 (20 once Free is released)
|
|
85
124
|
|
|
86
125
|
- **21 in the `TOOLS` array / parity test**: the `TOOLS` array in
|
|
87
126
|
`packages/metadata/src/mcp-tool-catalog.ts` defines 21 anonymous tools; the
|
|
88
127
|
parity test counts that full array. It also holds the eighteen signed-in
|
|
89
128
|
workspace tools (#3591), which no anonymous view returns — see § The
|
|
90
129
|
signed-in workspace surface below.
|
|
91
|
-
- **
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
`
|
|
97
|
-
|
|
98
|
-
|
|
130
|
+
- **19 registered on a KEYLESS deployment, 20 on a commerce-claimed one,
|
|
131
|
+
while the Free level is held — 20 and 21 once it is released**
|
|
132
|
+
(#5971, #9534): `createMcpServer` (`apps/mcp/src/server.ts`) registers
|
|
133
|
+
`getMcpToolRegistrations()` minus the topology seam's `UNSERVED_MCP_TOOLS`,
|
|
134
|
+
minus `create_project` while create-ailk's `release-scope.json` holds
|
|
135
|
+
`levels.free` (the release-scope filter, #9534), minus `OSS_DISABLED_TOOLS`
|
|
136
|
+
(now empty), minus module-gated tools whose module is off, minus any
|
|
137
|
+
`addon`-tagged tool whose claim this deployment does not hold.
|
|
138
|
+
`start_purchase` carries `addon: "commerce"`, so it is the one entry whose
|
|
139
|
+
presence depends on the licence — one fewer without the claim.
|
|
140
|
+
- **19 free anonymous tools while Free is held (20 released)**: since #5853 retired the three content-write
|
|
99
141
|
tools, every registered tool remains anonymous — call-time gating checks a
|
|
100
142
|
licence claim, never an identity. The six carrying `tier: "pro"`
|
|
101
143
|
(`get_flow`, `submit_flow_step`, `list_availability`, `get_event_meta`,
|
|
@@ -145,10 +187,11 @@ here. Spec: `docs/specs/3591-tenant-scoped-agent-auth-secure-spec.md` D13–D16.
|
|
|
145
187
|
price is refused `proposal_needs_person` (a person prices). Each takes its route's params, query and body and returns the route's
|
|
146
188
|
`data`. They are in the parity guard like every other tool, and never in
|
|
147
189
|
`/.well-known/mcp.json`.
|
|
148
|
-
- **Handlers forward, nothing else.** `workspace-server.ts` resolves each tool
|
|
149
|
-
|
|
150
|
-
`inbox_applications.ts`, `person_notes.ts`, `proposals.ts`, all
|
|
151
|
-
|
|
190
|
+
- **Handlers forward, nothing else.** `workspace-server.ts` resolves each tool from
|
|
191
|
+
`@working-theory/mcp-workspace`'s `workspaceTools` (`agent_context.ts`, `inbox_messages.ts`,
|
|
192
|
+
`inbox_submissions.ts`, `inbox_applications.ts`, `person_notes.ts`, `proposals.ts`, all
|
|
193
|
+
`// oss: false`), loaded through the site's generated registry, as `server.ts` resolves the
|
|
194
|
+
module-gated tools from their packs (#9460). Each calls `@working-theory/api-client`'s `inbox` surface
|
|
152
195
|
(the notes and proposals tools, its `people` surface) with the key. A refusal from the
|
|
153
196
|
route is an MCP tool error naming the route's `error.code` and HTTP status only.
|
|
154
197
|
- **Never log or return the key.** Don't log or serialise `extra`, `extra.authInfo` or
|
|
@@ -225,7 +268,11 @@ Example (lead routing):
|
|
|
225
268
|
- Don't add a tool without the matching `apps/api` endpoint.
|
|
226
269
|
- Don't put business logic in tool handlers — they're adapters.
|
|
227
270
|
|
|
228
|
-
Last updated: 2026-10-
|
|
271
|
+
Last updated: 2026-10-22 — #9460: the server is `@working-theory/mcp-server` and the paid tools ride `packages-paid/mcp-*`; `src/` is the five-file boot set, `lib/paid-tools.generated.ts` is the one door to a paid MCP package, and the specifier tables are gone — verified against `packages/mcp-server/src/{server,workspace-server,boot,run,site}.ts`, `apps/mcp/src/{index,app,site}.ts` and `packages/create-ailk/src/paid-sections.ts`.
|
|
272
|
+
|
|
273
|
+
Prior: 2026-10-22 — #9534: `create_project` registers only while create-ailk's `release-scope.json` marks the Free level released (the release-scope filter in `shouldRegister`, re-applied at call time) — 19 registered keyless and 20 claimed while Free is held — and the content-root rule names the tool's `<cwd>/packages/create-ailk` root as its standing exception — verified against `apps/mcp/src/tools/create_project.ts`, `apps/mcp/src/server.ts` and `apps/web/app/.well-known/mcp.json/route.ts`.
|
|
274
|
+
|
|
275
|
+
Prior: 2026-10-20 — #7171, #7172, #7173: the three lead writes adopted their routes' bodies and 201 results and are parity `twin`s — the Conversion-write line records the adopted shapes — verified against `apps/mcp/src/tools/{capture_lead,subscribe_newsletter,request_callback}.ts`, `packages/validation/src/schemas/leads.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
229
276
|
|
|
230
277
|
Prior: 2026-10-20 — #7167, #7168, #7169: the three content reads adopted their routes' arguments and results and are parity `twin`s — the Read line records the adopted shapes — verified against `apps/mcp/src/tools/{search_content,list_pages,read_content}.ts`, `packages/validation/src/schemas/content-reads.ts`, `packages/content-adapters/src/content-reads.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
231
278
|
|
|
@@ -24,124 +24,8 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { existsSync, readFileSync } from "node:fs";
|
|
27
|
-
import { createServer, type Server } from "node:http";
|
|
28
|
-
import type { AddressInfo } from "node:net";
|
|
29
27
|
import { resolve } from "node:path";
|
|
30
28
|
|
|
31
|
-
import Fastify, { type FastifyInstance } from "fastify";
|
|
32
|
-
|
|
33
|
-
import { buildHttpTransportApp } from "../src/http-transport.js";
|
|
34
|
-
import {
|
|
35
|
-
configureServerlessApp,
|
|
36
|
-
SERVERLESS_FASTIFY_OPTIONS,
|
|
37
|
-
serverlessHandler,
|
|
38
|
-
trustOneHop,
|
|
39
|
-
} from "../src/serverless-app.js";
|
|
40
|
-
|
|
41
|
-
// The hub call capture_lead makes after the guard is stubbed, as
|
|
42
|
-
// http-transport.test.ts stubs checkout: only the guard's verdict is asserted.
|
|
43
|
-
jest.mock("@working-theory/api-client", () => {
|
|
44
|
-
const actual = jest.requireActual("@working-theory/api-client");
|
|
45
|
-
return {
|
|
46
|
-
...actual,
|
|
47
|
-
apiClient: {
|
|
48
|
-
...actual.apiClient,
|
|
49
|
-
leads: {
|
|
50
|
-
...actual.apiClient.leads,
|
|
51
|
-
submit: jest.fn().mockResolvedValue({
|
|
52
|
-
ok: true,
|
|
53
|
-
body: {
|
|
54
|
-
id: "lead_00000000-0000-7000-8000-000000008070",
|
|
55
|
-
persisted: "db",
|
|
56
|
-
},
|
|
57
|
-
}),
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const VARS = [
|
|
64
|
-
"MCP_HTTP_STATELESS",
|
|
65
|
-
"MCP_ABUSE_CAPTURE_LEAD_DAILY_CAP",
|
|
66
|
-
"MCP_CORS_WRITE_ALLOWED_ORIGINS",
|
|
67
|
-
] as const;
|
|
68
|
-
|
|
69
|
-
const saved: Partial<Record<(typeof VARS)[number], string | undefined>> = {};
|
|
70
|
-
|
|
71
|
-
beforeEach(() => {
|
|
72
|
-
for (const name of VARS) {
|
|
73
|
-
saved[name] = process.env[name];
|
|
74
|
-
delete process.env[name];
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
afterEach(() => {
|
|
79
|
-
for (const name of VARS) {
|
|
80
|
-
const value = saved[name];
|
|
81
|
-
if (value === undefined) delete process.env[name];
|
|
82
|
-
else process.env[name] = value;
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
async function mcpPost(
|
|
87
|
-
port: number,
|
|
88
|
-
payload: object,
|
|
89
|
-
headers: Record<string, string> = {},
|
|
90
|
-
): Promise<Response> {
|
|
91
|
-
return fetch(`http://127.0.0.1:${port}/mcp`, {
|
|
92
|
-
method: "POST",
|
|
93
|
-
body: JSON.stringify(payload),
|
|
94
|
-
headers: {
|
|
95
|
-
"content-type": "application/json",
|
|
96
|
-
accept: "application/json, text/event-stream",
|
|
97
|
-
...headers,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function listen(app: FastifyInstance): Promise<number> {
|
|
103
|
-
await app.listen({ host: "127.0.0.1", port: 0 });
|
|
104
|
-
return (app.server.address() as AddressInfo).port;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** The app src/app.ts builds, minus the boot and the default export. */
|
|
108
|
-
async function serverlessApp(): Promise<FastifyInstance> {
|
|
109
|
-
const app = Fastify(SERVERLESS_FASTIFY_OPTIONS);
|
|
110
|
-
await configureServerlessApp(app);
|
|
111
|
-
await app.ready();
|
|
112
|
-
return app;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Serve the app through the exact function Vercel's Node runtime calls. */
|
|
116
|
-
async function serveHandler(
|
|
117
|
-
app: FastifyInstance,
|
|
118
|
-
): Promise<{ server: Server; port: number }> {
|
|
119
|
-
const server = createServer(serverlessHandler(app));
|
|
120
|
-
await new Promise<void>((done) => server.listen(0, "127.0.0.1", done));
|
|
121
|
-
return { server, port: (server.address() as AddressInfo).port };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function stop(server: Server | undefined): Promise<void> {
|
|
125
|
-
if (!server) return;
|
|
126
|
-
await new Promise<void>((done) => server.close(() => done()));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function captureLead(id: number, name: string): object {
|
|
130
|
-
return {
|
|
131
|
-
jsonrpc: "2.0",
|
|
132
|
-
id,
|
|
133
|
-
method: "tools/call",
|
|
134
|
-
params: {
|
|
135
|
-
name: "capture_lead",
|
|
136
|
-
arguments: {
|
|
137
|
-
source: "mcp",
|
|
138
|
-
email: `${name.toLowerCase()}@example.com`,
|
|
139
|
-
payload: { name, message: "Interested in your services." },
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
29
|
describe("AC-4 — src/app.ts, read as source text", () => {
|
|
146
30
|
const src = readFileSync(resolve(__dirname, "../src/app.ts"), "utf-8");
|
|
147
31
|
|
|
@@ -150,17 +34,17 @@ describe("AC-4 — src/app.ts, read as source text", () => {
|
|
|
150
34
|
});
|
|
151
35
|
|
|
152
36
|
it("awaits the shared boot, builds Fastify from the serverless options and configures it", () => {
|
|
153
|
-
expect(src).toContain("await bootMcp()");
|
|
37
|
+
expect(src).toContain("await bootMcp(site)");
|
|
154
38
|
expect(src).toContain("Fastify(SERVERLESS_FASTIFY_OPTIONS)");
|
|
155
|
-
expect(src).toContain("configureServerlessApp(app)");
|
|
39
|
+
expect(src).toContain("configureServerlessApp(app, site)");
|
|
156
40
|
});
|
|
157
41
|
|
|
158
42
|
it("boots before it builds the app, and readies it before it exports", () => {
|
|
159
|
-
expect(src.indexOf("await bootMcp()")).toBeLessThan(
|
|
43
|
+
expect(src.indexOf("await bootMcp(site)")).toBeLessThan(
|
|
160
44
|
src.indexOf("Fastify(SERVERLESS_FASTIFY_OPTIONS)"),
|
|
161
45
|
);
|
|
162
46
|
expect(src).toContain("await app.ready()");
|
|
163
|
-
expect(src.indexOf("configureServerlessApp(app)")).toBeLessThan(
|
|
47
|
+
expect(src.indexOf("configureServerlessApp(app, site)")).toBeLessThan(
|
|
164
48
|
src.indexOf("await app.ready()"),
|
|
165
49
|
);
|
|
166
50
|
});
|
|
@@ -189,137 +73,3 @@ describe("AC-13 — Vercel's type-check keeps strict", () => {
|
|
|
189
73
|
expect(existsSync(resolve(__dirname, "../vercel.json"))).toBe(false);
|
|
190
74
|
});
|
|
191
75
|
});
|
|
192
|
-
|
|
193
|
-
describe("AC-4 — the serverless options and the configured app", () => {
|
|
194
|
-
let app: FastifyInstance | undefined;
|
|
195
|
-
let server: Server | undefined;
|
|
196
|
-
let port = 0;
|
|
197
|
-
|
|
198
|
-
afterEach(async () => {
|
|
199
|
-
await stop(server);
|
|
200
|
-
await app?.close();
|
|
201
|
-
app = undefined;
|
|
202
|
-
server = undefined;
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("SERVERLESS_FASTIFY_OPTIONS is { logger: false, trustProxy: trustOneHop }", () => {
|
|
206
|
-
expect(SERVERLESS_FASTIFY_OPTIONS).toEqual({
|
|
207
|
-
logger: false,
|
|
208
|
-
trustProxy: trustOneHop,
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it("trustOneHop trusts the immediate peer (hop 0) and nothing behind it, whatever its address", () => {
|
|
213
|
-
expect(trustOneHop("127.0.0.1", 0)).toBe(true);
|
|
214
|
-
expect(trustOneHop("10.0.0.1", 0)).toBe(true);
|
|
215
|
-
expect(trustOneHop("9.9.9.9", 1)).toBe(false);
|
|
216
|
-
expect(trustOneHop("1.1.1.1", 2)).toBe(false);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it("why not trustProxy: 1 — this Fastify treats a numeric hop count as trust-nothing", async () => {
|
|
220
|
-
const numeric = Fastify({ logger: false, trustProxy: 1 });
|
|
221
|
-
numeric.get("/ip", async (request) => ({ ip: request.ip }));
|
|
222
|
-
const res = await numeric.inject({
|
|
223
|
-
url: "/ip",
|
|
224
|
-
remoteAddress: "127.0.0.1",
|
|
225
|
-
headers: { "x-forwarded-for": "3.3.3.3, 8.8.8.8" },
|
|
226
|
-
});
|
|
227
|
-
await numeric.close();
|
|
228
|
-
|
|
229
|
-
// Every caller would key on the edge's address.
|
|
230
|
-
expect(res.json()).toEqual({ ip: "127.0.0.1" });
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it("serverlessHandler(app) is a (req, res) function", async () => {
|
|
234
|
-
app = await serverlessApp();
|
|
235
|
-
expect(typeof serverlessHandler(app)).toBe("function");
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it("with MCP_HTTP_STATELESS unset, an http.createServer serving serverlessHandler(app) answers initialize and then a session-less tools/list", async () => {
|
|
239
|
-
app = await serverlessApp();
|
|
240
|
-
({ server, port } = await serveHandler(app));
|
|
241
|
-
|
|
242
|
-
const init = await mcpPost(port, {
|
|
243
|
-
jsonrpc: "2.0",
|
|
244
|
-
id: 1,
|
|
245
|
-
method: "initialize",
|
|
246
|
-
params: {
|
|
247
|
-
protocolVersion: "2025-03-26",
|
|
248
|
-
capabilities: {},
|
|
249
|
-
clientInfo: { name: "app-entry-test", version: "1.0.0" },
|
|
250
|
-
},
|
|
251
|
-
});
|
|
252
|
-
expect(init.status).toBe(200);
|
|
253
|
-
const initBody = (await init.json()) as {
|
|
254
|
-
result?: { serverInfo?: { name?: string } };
|
|
255
|
-
};
|
|
256
|
-
expect(initBody.result?.serverInfo).toMatchObject({ name: "ailk" });
|
|
257
|
-
|
|
258
|
-
const list = await mcpPost(port, {
|
|
259
|
-
jsonrpc: "2.0",
|
|
260
|
-
id: 2,
|
|
261
|
-
method: "tools/list",
|
|
262
|
-
params: {},
|
|
263
|
-
});
|
|
264
|
-
expect(list.status).toBe(200);
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
describe("AC-5 — the daily cap keys on the last X-Forwarded-For hop", () => {
|
|
269
|
-
let app: FastifyInstance | undefined;
|
|
270
|
-
let server: Server | undefined;
|
|
271
|
-
|
|
272
|
-
afterEach(async () => {
|
|
273
|
-
await stop(server);
|
|
274
|
-
await app?.close();
|
|
275
|
-
app = undefined;
|
|
276
|
-
server = undefined;
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("serverless app: two callers sharing a last hop are one caller; a different last hop is another", async () => {
|
|
280
|
-
process.env["MCP_ABUSE_CAPTURE_LEAD_DAILY_CAP"] = "1";
|
|
281
|
-
// Set explicitly so the write-origin check is never what refuses a call.
|
|
282
|
-
process.env["MCP_CORS_WRITE_ALLOWED_ORIGINS"] = "*";
|
|
283
|
-
app = await serverlessApp();
|
|
284
|
-
const { server: served, port } = await serveHandler(app);
|
|
285
|
-
server = served;
|
|
286
|
-
|
|
287
|
-
const first = await mcpPost(port, captureLead(10, "First"), {
|
|
288
|
-
"x-forwarded-for": "1.1.1.1, 9.9.9.9",
|
|
289
|
-
});
|
|
290
|
-
expect(first.status).toBe(200);
|
|
291
|
-
|
|
292
|
-
const second = await mcpPost(port, captureLead(11, "Second"), {
|
|
293
|
-
"x-forwarded-for": "2.2.2.2, 9.9.9.9",
|
|
294
|
-
});
|
|
295
|
-
expect(second.status).toBe(403);
|
|
296
|
-
const refusal = (await second.json()) as { error?: string };
|
|
297
|
-
expect(refusal.error).toBe("daily capture_lead cap reached for this IP");
|
|
298
|
-
|
|
299
|
-
const third = await mcpPost(port, captureLead(12, "Third"), {
|
|
300
|
-
"x-forwarded-for": "3.3.3.3, 8.8.8.8",
|
|
301
|
-
});
|
|
302
|
-
expect(third.status).toBe(200);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it("long-running app (no trustProxy): the header is ignored — every call is the socket's address", async () => {
|
|
306
|
-
app = await buildHttpTransportApp({
|
|
307
|
-
path: "/mcp",
|
|
308
|
-
stateless: true,
|
|
309
|
-
rateLimits: { readPerMin: 60, writePerMin: 10 },
|
|
310
|
-
cors: { writeAllowedOrigins: ["*"] },
|
|
311
|
-
abuse: { captureLeadDailyCapPerIp: 1, blockedUserAgents: "" },
|
|
312
|
-
});
|
|
313
|
-
const port = await listen(app);
|
|
314
|
-
|
|
315
|
-
const first = await mcpPost(port, captureLead(20, "First"), {
|
|
316
|
-
"x-forwarded-for": "3.3.3.3",
|
|
317
|
-
});
|
|
318
|
-
expect(first.status).toBe(200);
|
|
319
|
-
|
|
320
|
-
const second = await mcpPost(port, captureLead(21, "Second"), {
|
|
321
|
-
"x-forwarded-for": "4.4.4.4",
|
|
322
|
-
});
|
|
323
|
-
expect(second.status).toBe(403);
|
|
324
|
-
});
|
|
325
|
-
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The boot set is a boot set (#9460 AC-1 (a)).
|
|
3
|
+
*
|
|
4
|
+
* Every file under `src/` may import only `@working-theory/mcp-server`, its
|
|
5
|
+
* `/hub` entry, `fastify`, the type-only `@working-theory/content-adapters`,
|
|
6
|
+
* the site's own `./site.js` and `./lib/*.generated.js` — and, inside
|
|
7
|
+
* `lib/paid-tools.generated.ts` alone, the paid MCP packs. A boot file that
|
|
8
|
+
* imported `@working-theory/validation`, `@working-theory/api-client` or a
|
|
9
|
+
* tool module would rebuild the coupling that broke 0.45.0; a deep import
|
|
10
|
+
* such as `@working-theory/mcp-server/dist/tools/get_faq.js` is one a bump
|
|
11
|
+
* would not keep stable. This suite ships to every scaffold, so a keyless
|
|
12
|
+
* site re-checks itself.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
16
|
+
import { join, relative, resolve } from "node:path";
|
|
17
|
+
|
|
18
|
+
const SRC = resolve(__dirname, "../src");
|
|
19
|
+
|
|
20
|
+
const ALLOWED = new Set([
|
|
21
|
+
"@working-theory/mcp-server",
|
|
22
|
+
"@working-theory/mcp-server/hub",
|
|
23
|
+
"fastify",
|
|
24
|
+
"@working-theory/content-adapters",
|
|
25
|
+
]);
|
|
26
|
+
const PAID_PACKS = new Set([
|
|
27
|
+
"@working-theory/mcp-scheduling",
|
|
28
|
+
"@working-theory/mcp-signal-collectors",
|
|
29
|
+
"@working-theory/mcp-workspace",
|
|
30
|
+
]);
|
|
31
|
+
const REGISTRY = "lib/paid-tools.generated.ts";
|
|
32
|
+
|
|
33
|
+
function walk(dir: string, out: string[] = []): string[] {
|
|
34
|
+
for (const entry of readdirSync(dir)) {
|
|
35
|
+
const p = join(dir, entry);
|
|
36
|
+
if (statSync(p).isDirectory()) walk(p, out);
|
|
37
|
+
else if (p.endsWith(".ts")) out.push(p);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Every static and dynamic import specifier in `text`. */
|
|
43
|
+
function specifiers(text: string): string[] {
|
|
44
|
+
return [...text.matchAll(/(?:from|import)\s*\(?\s*"([^"]+)"/g)].map(
|
|
45
|
+
(m) => m[1]!,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function allowedFor(file: string, spec: string): boolean {
|
|
50
|
+
if (ALLOWED.has(spec)) return true;
|
|
51
|
+
if (spec === "./site.js" || /^\.\/lib\/[\w-]+\.generated\.js$/.test(spec))
|
|
52
|
+
return true;
|
|
53
|
+
return file === REGISTRY && PAID_PACKS.has(spec);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("apps/mcp/src is the boot set (#9460 AC-1)", () => {
|
|
57
|
+
const files = walk(SRC).map((p) => relative(SRC, p).split("\\").join("/"));
|
|
58
|
+
|
|
59
|
+
it("holds exactly the five boot files", () => {
|
|
60
|
+
expect(files.sort()).toEqual([
|
|
61
|
+
"app.ts",
|
|
62
|
+
"index.ts",
|
|
63
|
+
"lib/paid-tools.generated.ts",
|
|
64
|
+
"lib/topology.generated.ts",
|
|
65
|
+
"site.ts",
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it.each(files)(
|
|
70
|
+
"%s imports only the package, fastify and the site's own files",
|
|
71
|
+
(file) => {
|
|
72
|
+
const text = readFileSync(join(SRC, file), "utf8");
|
|
73
|
+
const specs = specifiers(text);
|
|
74
|
+
expect(specs.filter((spec) => !allowedFor(file, spec))).toEqual([]);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
it("no boot file imports a tool, a schema or the api client", () => {
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
const specs = specifiers(readFileSync(join(SRC, file), "utf8"));
|
|
81
|
+
expect(
|
|
82
|
+
specs.filter(
|
|
83
|
+
(spec) =>
|
|
84
|
+
spec.includes("/dist/") ||
|
|
85
|
+
spec.includes("/tools/") ||
|
|
86
|
+
spec === "@working-theory/validation" ||
|
|
87
|
+
spec === "@working-theory/api-client",
|
|
88
|
+
),
|
|
89
|
+
).toEqual([]);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
// Only so the handler suite's spawned create-ailk CLI scaffolds keyless (Free
|
|
2
|
+
// is held): the registration gate (`isFreeLevelReleased`) never reads it (#9534).
|
|
3
|
+
process.env.AILK_RELEASE_SCOPE = "ignore";
|
|
4
|
+
|
|
1
5
|
module.exports = {
|
|
2
6
|
preset: 'ts-jest',
|
|
3
7
|
globalSetup: require.resolve('../../tools/jest/pin-timezone.cjs'),
|
|
8
|
+
reporters: require('../../tools/jest/reporters.cjs'),
|
|
4
9
|
testEnvironment: 'node',
|
|
5
10
|
// Workaround: @hono/node-server@1.19.14 (transitive via
|
|
6
11
|
// @modelcontextprotocol/sdk's StreamableHTTPServerTransport) calls
|
|
@@ -21,7 +26,7 @@ module.exports = {
|
|
|
21
26
|
// fresh checkout, and the published dist is ESM, which Jest's CJS preset
|
|
22
27
|
// can't load. The CLIENT root (`@working-theory/database`) stays
|
|
23
28
|
// deliberately UNMAPPED — see apps/mcp/src/lib/prisma.ts.
|
|
24
|
-
'^@working-theory/database/tenancy$': '<rootDir
|
|
29
|
+
'^@working-theory/database/tenancy$': '<rootDir>/node_modules/@working-theory/database/dist/tenancy.js',
|
|
25
30
|
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
26
31
|
},
|
|
27
32
|
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts'],
|
|
@@ -16,25 +16,17 @@
|
|
|
16
16
|
"test:coverage": "jest --coverage"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@fastify/cors": "^11.2.0",
|
|
20
|
-
"@fastify/rate-limit": "^10.3.0",
|
|
21
|
-
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
22
19
|
"@prisma/adapter-pg": "^7.8.0",
|
|
23
|
-
"@working-theory/aeo": "workspace:*",
|
|
24
|
-
"@working-theory/api-client": "workspace:*",
|
|
25
20
|
"@working-theory/content-adapters": "workspace:*",
|
|
26
21
|
"@working-theory/database": "workspace:*",
|
|
27
|
-
"@working-theory/
|
|
28
|
-
"
|
|
29
|
-
"@working-theory/schema": "workspace:*",
|
|
30
|
-
"@working-theory/site-config": "workspace:*",
|
|
31
|
-
"@working-theory/validation": "workspace:*",
|
|
32
|
-
"fastify": "^5.12.5",
|
|
33
|
-
"yaml": "^2.9.0",
|
|
34
|
-
"zod": "^4.2.1"
|
|
22
|
+
"@working-theory/mcp-server": "workspace:*",
|
|
23
|
+
"fastify": "^5.12.5"
|
|
35
24
|
},
|
|
36
25
|
"devDependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
37
27
|
"@types/jest": "^30.0.0",
|
|
28
|
+
"@working-theory/api-client": "workspace:*",
|
|
29
|
+
"@working-theory/metadata": "workspace:*",
|
|
38
30
|
"@types/node": "^22.20.0",
|
|
39
31
|
"jest": "^30.4.2",
|
|
40
32
|
"ts-jest": "^29.4.11",
|
|
@@ -10,23 +10,24 @@
|
|
|
10
10
|
* warm instance reuses the booted app.
|
|
11
11
|
*
|
|
12
12
|
* Run locally, use `src/index.ts` (stdio, or HTTP on MCP_HTTP_PORT) instead.
|
|
13
|
-
* Everything testable lives in `
|
|
13
|
+
* Everything testable lives in `@working-theory/mcp-server` (#9460).
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import Fastify from "fastify";
|
|
17
|
-
|
|
18
|
-
import { bootMcp } from "./boot.js";
|
|
19
16
|
import {
|
|
17
|
+
bootMcp,
|
|
20
18
|
configureServerlessApp,
|
|
21
19
|
SERVERLESS_FASTIFY_OPTIONS,
|
|
22
20
|
serverlessHandler,
|
|
23
|
-
} from "
|
|
21
|
+
} from "@working-theory/mcp-server";
|
|
22
|
+
import Fastify from "fastify";
|
|
23
|
+
|
|
24
|
+
import { site } from "./site.js";
|
|
24
25
|
|
|
25
26
|
/** Read statically by Vercel's Node builder; caps one request (S8070-03). */
|
|
26
27
|
export const config = { maxDuration: 30 };
|
|
27
28
|
|
|
28
|
-
await bootMcp();
|
|
29
|
+
await bootMcp(site);
|
|
29
30
|
const app = Fastify(SERVERLESS_FASTIFY_OPTIONS);
|
|
30
|
-
await configureServerlessApp(app);
|
|
31
|
+
await configureServerlessApp(app, site);
|
|
31
32
|
await app.ready();
|
|
32
33
|
export default serverlessHandler(app);
|
|
@@ -23,41 +23,13 @@
|
|
|
23
23
|
* CONTENT_ADAPTER=mdx|projection|database
|
|
24
24
|
* DATABASE_URL= (required only when CONTENT_ADAPTER=database)
|
|
25
25
|
*
|
|
26
|
-
* The
|
|
27
|
-
* the
|
|
26
|
+
* The server is `@working-theory/mcp-server` (#9460): the boot sequence, the
|
|
27
|
+
* transports and every tool come from the package, so a version bump of it is
|
|
28
|
+
* the whole of taking an MCP change. This file hands it the site.
|
|
28
29
|
*/
|
|
29
30
|
|
|
30
|
-
import {
|
|
31
|
-
bootMcp,
|
|
32
|
-
httpTransportConfigFromEnv,
|
|
33
|
-
readStatelessEnv,
|
|
34
|
-
} from "./boot.js";
|
|
31
|
+
import { runMcp } from "@working-theory/mcp-server";
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
// and the licence boot warning — before either transport branch below.
|
|
38
|
-
await bootMcp();
|
|
33
|
+
import { site } from "./site.js";
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (transport === "http") {
|
|
43
|
-
const { startHttpTransport } = await import("./http-transport.js");
|
|
44
|
-
|
|
45
|
-
const config = httpTransportConfigFromEnv();
|
|
46
|
-
await startHttpTransport({
|
|
47
|
-
...config,
|
|
48
|
-
stateless: readStatelessEnv(false),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
console.log(
|
|
52
|
-
`MCP HTTP transport listening on port ${config.port} at ${config.path}`,
|
|
53
|
-
);
|
|
54
|
-
} else {
|
|
55
|
-
// Default: stdio transport
|
|
56
|
-
const { StdioServerTransport } =
|
|
57
|
-
await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
58
|
-
const { createMcpServer } = await import("./server.js");
|
|
59
|
-
|
|
60
|
-
const server = createMcpServer();
|
|
61
|
-
const stdioTransport = new StdioServerTransport();
|
|
62
|
-
await server.connect(stdioTransport);
|
|
63
|
-
}
|
|
35
|
+
await runMcp(site);
|