create-ailk 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -22
- 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 +2 -1
- package/dist/lib/fetch-template-snapshot.js +8 -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 +36 -15
- package/dist/lib/module-tier.d.ts +2 -8
- package/dist/lib/module-tier.js +13 -12
- package/dist/module-architecture.d.ts +20 -3
- package/dist/module-architecture.js +129 -552
- package/dist/paid-sections.d.ts +25 -1
- package/dist/paid-sections.js +88 -3
- package/dist/starter-grid.d.ts +6 -6
- package/dist/starter-grid.js +12 -5
- package/dist/surfaces.js +39 -2
- package/dist/template-record.d.ts +21 -3
- package/dist/template-record.js +38 -7
- package/dist/topology.d.ts +16 -3
- package/dist/topology.js +54 -23
- package/dist/update.d.ts +10 -1
- package/dist/update.js +715 -21
- package/package.json +3 -3
- package/release-scope.json +2 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +8 -2
- package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +2 -2
- package/site-templates/marketing-site/ailk-template.json +7 -1
- package/site-templates/marketing-site/provenance.json +7 -1
- package/site-templates/saas-product/ailk-template.json +2 -1
- package/site-templates/saas-product/provenance.json +1 -0
- 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 +20 -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 +23 -2
- package/templates/apps/api/CLAUDE.md +119 -83
- 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-client.js +16 -0
- 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 +90 -26
- 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 +31 -3
- package/templates/apps/web/app/.well-known/mcp.json/route.ts +9 -3
- package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +43 -4
- package/templates/apps/web/app/[locale]/(auth)/legal-footnote.tsx +35 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-in/__tests__/page.test.tsx +117 -8
- package/templates/apps/web/app/[locale]/(auth)/sign-in/page.tsx +14 -37
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +6 -6
- package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-text.ts +20 -35
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/page.test.tsx +108 -0
- package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +111 -5
- package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +78 -16
- package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +132 -12
- package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +53 -1
- package/templates/apps/web/app/[locale]/(authed)/account/__tests__/billing.test.tsx +38 -0
- package/templates/apps/web/app/[locale]/(authed)/account/billing/page.tsx +4 -2
- package/templates/apps/web/app/[locale]/(authed)/sign-in-gate.tsx +47 -24
- package/templates/apps/web/app/[locale]/(authed)/signed-out-gate.generated.tsx +23 -4
- 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]/layout.tsx +33 -13
- package/templates/apps/web/app/[locale]/meet/confirmed/BookingHandOff.tsx +128 -0
- package/templates/apps/web/app/[locale]/meet/confirmed/__tests__/BookingHandOff.test.tsx +126 -0
- 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 +10 -6
- package/templates/apps/web/i18n/request.ts +49 -1
- package/templates/apps/web/jest.config.cjs +1 -0
- package/templates/apps/web/lib/__tests__/account-config.test.ts +7 -0
- package/templates/apps/web/lib/__tests__/auth-email.test.ts +276 -0
- package/templates/apps/web/lib/auth-email.ts +103 -21
- package/templates/apps/web/lib/hub-session/__tests__/sign-in-gate.test.tsx +72 -23
- package/templates/apps/web/lib/hub-session/sign-in-gate.tsx +94 -70
- package/templates/apps/web/lib/prisma-for-auth.ts +5 -2
- 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/lib/sign-up-agreements.ts +291 -28
- package/templates/apps/web/lib/site-contributions.ts +18 -0
- package/templates/apps/web/messages/en.json +186 -20
- package/templates/apps/web/messages/site/en.json +1 -0
- 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 +49 -36
- 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
|
-
parity test counts that full array. It also holds the
|
|
127
|
+
parity test counts that full array. It also holds the thirty-one 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`,
|
|
@@ -128,28 +170,38 @@ here. Spec: `docs/specs/3591-tenant-scoped-agent-auth-secure-spec.md` D13–D16.
|
|
|
128
170
|
- **apps/mcp checks only the key's shape.** The key is attached as the SDK's `req.auth` for that
|
|
129
171
|
request alone and reaches a tool as `extra.authInfo.token`. apps/api is the one place it is
|
|
130
172
|
checked, and its tenant guard and the caller's clamped role decide every answer.
|
|
131
|
-
- **
|
|
173
|
+
- **Thirty-one tools, each a `twin`.** The catalog rows carry `surface: "workspace"`, `tier: "pro"`
|
|
132
174
|
and `modulesAnyOf` (the modules any one of which registers the tool — its twin route's gate):
|
|
133
|
-
`get_agent_context`,
|
|
175
|
+
`get_agent_context`, (#9683) `get_workspace_knowledge` — twin of `GET
|
|
176
|
+
/v1/workspaces/:workspaceId/knowledge`: the business's shown offerings, live magnets, listed
|
|
177
|
+
meeting types, sites served and strategy documents, read with the `people-read` or
|
|
178
|
+
`people-memory-propose` grant — the five message tools (#9686 added `list_inbox_threads`, twin of
|
|
179
|
+
`GET …/messages/threads`: the inbox's threads, 25 to a page with a count per view; Done now
|
|
180
|
+
archives the message's thread and accept no longer marks it done, and an agent reaches any
|
|
181
|
+
inbox tool only with the `inbox-act` grant), the three submission tools, the three
|
|
134
182
|
listing application tools (#9137: `list_listing_applications`, `get_listing_application`,
|
|
135
183
|
`decide_listing_application` — a `ProjectListing` row, never a job application, which is a Job
|
|
136
184
|
application magnet's submission; the pre-rename `list_inbox_applications`,
|
|
137
185
|
`get_inbox_application` and `decide_inbox_application` stay registered for one release as
|
|
138
|
-
deprecated aliases of the same handlers, each description opening `Deprecated: use …`) and (#8514) the two People notes tools, `get_person_notes` and
|
|
186
|
+
deprecated aliases of the same handlers, each description opening `Deprecated: use …`) and (#9714) `list_people` — twin of `GET /v1/workspaces/:workspaceId/people` in both its modes: newest-first pages by `cursor`, or with `changedSince` the clients whose thread gained an inbound item since then, oldest first with `more`, needing the `people-read` grant — and (#8514) the two People notes tools, `get_person_notes` and
|
|
139
187
|
`set_person_notes` — the team's private note on one client, which an agent reads and writes
|
|
140
188
|
only with the `member-pieces-manage` grant; `set_person_notes` requires the `ifUpdatedAt` it
|
|
141
189
|
read and is refused `notes_changed` when someone saved since — and (#8516) the two proposals
|
|
142
190
|
tools, `list_proposals` and `create_proposal`, twinning `GET`/`POST
|
|
143
191
|
/v1/workspaces/:workspaceId/people/:personId/proposals` with the same grant: a proposal is
|
|
144
192
|
private to one client, `payments` says whether approval leads to a Stripe page, and an agent's
|
|
145
|
-
price is refused `proposal_needs_person` (a person prices)
|
|
193
|
+
price is refused `proposal_needs_person` (a person prices) — and (#9681) the four person-thread tools, `get_person_thread`, `set_person_thread_state`, `list_external_threads` and `add_external_thread`, twinning `GET`/`PATCH …/people/:personId/thread` and `GET`/`POST …/people/:personId/external-threads`: a client's whole thread page by page with its read/archived/resolved state, and pointers to email and Slack threads (never message text); reading needs the `people-read` grant, writing also `inbox-act`, and the client erasure route has no tool, by decision — and (#9682) the three person-memory tools, `list_person_memories`, `get_person_memory` and `propose_person_memory`, twinning `GET …/people/:personId/memories`, `GET …/memories/:path` and `POST …/memories`: an agent reads only live, unexpired memories (confirmed by a person, read within 180 days) and its proposal is never live — a new path is a draft, a confirmed one gets a pending version — needing the `people-read` or `people-memory-propose` grant to read and `people-memory-propose` to propose; the six person-only memory routes (edit, delete, confirm, redact, the versions list, restore) have no tool, by decision — and (#9749) `get_slack_connection_status`, twin of `GET /v1/workspaces/:workspaceId/slack-connection` (registered with `workspace`/`multi-tenant`, its route's `TENANCY` row: whether the Organization's Slack is connected, its team name and the date, never a credential; connect and disconnect are a person's act and have no tool, by decision), and `get_prospect_channel_settings` / `set_prospect_channel_settings`, twins of `GET`/`PUT …/prospect-channel` (registered with `scheduling`, their routes' module): the update replaces every field, needs the `meeting-types-manage` grant, is refused `slack_not_connected` while the Organization has no Slack connection, and an agent may change only `enabled`, `channelPrefix` and `archiveDays` — a change to `memberIds` or `welcomeTemplate` is refused `prospect_channel_needs_person`. Each takes its route's params, query and body and returns the route's
|
|
146
194
|
`data`. They are in the parity guard like every other tool, and never in
|
|
147
195
|
`/.well-known/mcp.json`.
|
|
148
|
-
- **Handlers forward, nothing else.** `workspace-server.ts` resolves each tool
|
|
149
|
-
|
|
150
|
-
`inbox_applications.ts`, `person_notes.ts`, `
|
|
151
|
-
|
|
152
|
-
(
|
|
196
|
+
- **Handlers forward, nothing else.** `workspace-server.ts` resolves each tool from
|
|
197
|
+
`@working-theory/mcp-workspace`'s `workspaceTools` (`agent_context.ts`, `knowledge.ts`, `inbox_messages.ts`,
|
|
198
|
+
`inbox_submissions.ts`, `inbox_applications.ts`, `people_list.ts`, `person_notes.ts`, `person_thread.ts`, `person_memory.ts`, `proposals.ts`, `slack_connection.ts`, all
|
|
199
|
+
`// oss: false`) and, for the two prospect-channel settings tools, `@working-theory/mcp-scheduling`'s
|
|
200
|
+
`workspaceTools` (`prospect_channel_settings.ts`, #9749 — the pack the scheduling module carries, so a
|
|
201
|
+
scheduling-only build serves what it lists), loaded through the site's generated registry, as `server.ts` resolves the
|
|
202
|
+
module-gated tools from their packs (#9460). Each calls `@working-theory/api-client`'s `inbox` surface
|
|
203
|
+
(the people-list, notes, person-thread, person-memory and proposals tools, its `people` surface; the
|
|
204
|
+
Slack status and prospect-channel tools, its `slack` surface) with the key. A refusal from the
|
|
153
205
|
route is an MCP tool error naming the route's `error.code` and HTTP status only.
|
|
154
206
|
- **Never log or return the key.** Don't log or serialise `extra`, `extra.authInfo` or
|
|
155
207
|
`extra.requestInfo` — the SDK puts the raw `authorization` header there.
|
|
@@ -225,7 +277,19 @@ Example (lead routing):
|
|
|
225
277
|
- Don't add a tool without the matching `apps/api` endpoint.
|
|
226
278
|
- Don't put business logic in tool handlers — they're adapters.
|
|
227
279
|
|
|
228
|
-
Last updated: 2026-10-
|
|
280
|
+
Last updated: 2026-10-24 — #9749: `get_slack_connection_status` (`mcp-workspace`'s `slack_connection.ts`) and `get_prospect_channel_settings` / `set_prospect_channel_settings` (`mcp-scheduling`'s `prospect_channel_settings.ts`, the first signed-in handlers outside `mcp-workspace`) twin the Slack status read and the prospect-channel settings pair — the signed-in workspace surface is thirty-one tools — verified against `packages/metadata/src/mcp-tool-catalog.ts`, `packages-paid/mcp-workspace/src/index.ts`, `packages-paid/mcp-scheduling/src/index.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
281
|
+
|
|
282
|
+
Prior: 2026-10-24 — #9714: `list_people` (`people_list.ts`) twins `GET /v1/workspaces/:workspaceId/people` in both its modes — the signed-in workspace surface is twenty-eight tools — verified against `packages/metadata/src/mcp-tool-catalog.ts`, `packages-paid/mcp-workspace/src/index.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
283
|
+
|
|
284
|
+
Prior: 2026-10-24 — #9686: `list_inbox_threads` (`inbox_messages.ts`) twins `GET /v1/workspaces/:workspaceId/messages/threads` — the signed-in workspace surface is twenty-seven tools — verified against `packages/metadata/src/mcp-tool-catalog.ts`, `packages-paid/mcp-workspace/src/index.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
285
|
+
|
|
286
|
+
Prior: 2026-10-24 — #9683: `get_workspace_knowledge` (`knowledge.ts`) twins `GET /v1/workspaces/:workspaceId/knowledge` — the signed-in workspace surface is twenty-three tools; the inbox write twins forward no agent-session header — verified against `packages/metadata/src/mcp-tool-catalog.ts`, `packages-paid/mcp-workspace/src/index.ts` and `tests/parity/api-parity/kinds/site.ts`.
|
|
287
|
+
|
|
288
|
+
Prior: 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`.
|
|
289
|
+
|
|
290
|
+
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`.
|
|
291
|
+
|
|
292
|
+
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
293
|
|
|
230
294
|
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
295
|
|
|
@@ -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",
|