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
|
@@ -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);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// paid-tools.generated.ts — the paid MCP tool packages this site carries.
|
|
2
|
+
//
|
|
3
|
+
// GENERATED by create-ailk from MODULE_SLICES (`paidMcpToolPackages`) and
|
|
4
|
+
// this app's package.json dependencies (#9460). Do not edit: every scaffold
|
|
5
|
+
// and `create-ailk add-module` rewrites it. A carried package is a bundled
|
|
6
|
+
// dynamic import the server resolves its paid tools from at call time; a
|
|
7
|
+
// site that carries none exports an empty list.
|
|
8
|
+
import type { McpToolPackLoader } from "@working-theory/mcp-server";
|
|
9
|
+
|
|
10
|
+
export const PAID_TOOL_PACKS: readonly McpToolPackLoader[] = [];
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
initMcpPublicWorkspace,
|
|
11
11
|
mcpPublicWorkspace,
|
|
12
12
|
type McpWorkspaceResolution,
|
|
13
|
-
} from "
|
|
13
|
+
} from "@working-theory/mcp-server/hub";
|
|
14
14
|
|
|
15
|
-
export { registerLicenseKeyStore } from "
|
|
15
|
+
export { registerLicenseKeyStore } from "@working-theory/mcp-server/hub";
|
|
16
16
|
export type { McpWorkspaceResolution };
|
|
17
17
|
|
|
18
18
|
export const TOPOLOGY: "hub" | "spoke" = "hub";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The site this MCP server runs for (#9460 DD2/DD4): the topology seam and
|
|
3
|
+
* the paid-tool registry, both generated by create-ailk, handed to
|
|
4
|
+
* `@working-theory/mcp-server` as one object. Nothing else is the site's own.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { McpSite } from "@working-theory/mcp-server";
|
|
8
|
+
|
|
9
|
+
import { PAID_TOOL_PACKS } from "./lib/paid-tools.generated.js";
|
|
10
|
+
import * as topology from "./lib/topology.generated.js";
|
|
11
|
+
|
|
12
|
+
export const site: McpSite = { topology, paidToolPacks: PAID_TOOL_PACKS };
|
|
@@ -229,7 +229,7 @@ CONTENT_ADAPTER=mdx
|
|
|
229
229
|
# AILK_HUB_SIGN_IN_URL=https://hub.example.com
|
|
230
230
|
#
|
|
231
231
|
# This site's client id and secret, issued on the hub with
|
|
232
|
-
# pnpm --filter @working-theory/api spokes sign-in-client --id <spoke_id> \
|
|
232
|
+
# pnpm --filter @working-theory/app-api spokes sign-in-client --id <spoke_id> \
|
|
233
233
|
# --redirect-uri <this site's origin>/api/hub-session/callback
|
|
234
234
|
# The client id is the spoke's id. The secret is shown once; keep it out of git.
|
|
235
235
|
# AILK_HUB_CLIENT_ID=
|
|
@@ -130,6 +130,25 @@ older hub's 404). The carried `__Host-ailk-signup-agreements` cookie is
|
|
|
130
130
|
retired. Policy links on every agreement surface come from
|
|
131
131
|
`lib/consent-policies.ts`'s `consentPoliciesFor(locale)`.
|
|
132
132
|
|
|
133
|
+
**A magic link can create the account while sign-up is open (#9667).** With
|
|
134
|
+
the email sign-in link on, an open `/sign-up` is the one-field "Send me a
|
|
135
|
+
magic link" body (the page's method is `magic-link` before `password`), and
|
|
136
|
+
the card POSTs `/api/auth/sign-in/magic-link` with the ticked agreements and
|
|
137
|
+
locale in `metadata`. A request carrying that key is a sign-up request: the
|
|
138
|
+
plugin refuses it `400 SIGN_UP_CLOSED` on a closed site and
|
|
139
|
+
`400 AGREEMENTS_REQUIRED` without the agreements, before any lookup; the
|
|
140
|
+
callback binds the accepted agreements to the token (a `verification` row
|
|
141
|
+
keyed on SHA-256 of the token) and mails the address whether or not it has
|
|
142
|
+
an account (`userId: "sign-up"` for a new one). The plugin's
|
|
143
|
+
`disableSignUp` follows `isSignUpOpen()`. On verify, the user hook refuses —
|
|
144
|
+
a redirect to `/sign-up?error=AGREEMENTS_REQUIRED` — a new user whose token
|
|
145
|
+
has no binding or whose binding no longer covers the evidence, and the
|
|
146
|
+
session hook writes the grants in their own transaction before the session
|
|
147
|
+
exists, deleting the user if that write fails. A request with no `metadata`
|
|
148
|
+
(every `/sign-in` one) is a sign-in, unchanged. Not one transaction: a crash
|
|
149
|
+
between the user and grant inserts leaves a user with no grant, whom the
|
|
150
|
+
account interstitial stops.
|
|
151
|
+
|
|
133
152
|
## Contact page
|
|
134
153
|
|
|
135
154
|
The contact page (`apps/web/app/[locale]/contact/page.tsx`) renders the
|
|
@@ -407,7 +426,8 @@ Every multi-step magnet is a page pair (#8840), rendered by one module,
|
|
|
407
426
|
content. With none, #8848 D6 holds for a configured hub: a 5xx or a refused
|
|
408
427
|
connection shows the contact email (`noindex`). A site with no hub to ask —
|
|
409
428
|
the read answers 503 `flows_not_configured`, or no API origin
|
|
410
|
-
(`AILK_API_URL`,
|
|
429
|
+
(`AILK_API_URL`, the origin `browserApiOrigin()` returns, or
|
|
430
|
+
`NEXT_PUBLIC_API_URL`) is set —
|
|
411
431
|
reads `not-configured` (set once in `readMagnet`), and the slug 404s, as
|
|
412
432
|
does its `/start` (#9219). `/downloads` and `/downloads/<slug>` are
|
|
413
433
|
permanent redirects into `/reports` (signal-collectors files).
|
|
@@ -426,7 +446,11 @@ key), so the page names none. It renders one of three pages:
|
|
|
426
446
|
- **Unconnected** — the route answers `unconnected`, or the deployment runs
|
|
427
447
|
in production with none of the API origin variables `getApiBase()` reads:
|
|
428
448
|
today's MDX page through `renderPage`, byte for byte, `?plan=` matching
|
|
429
|
-
authored plan keys as #8842 made it.
|
|
449
|
+
authored plan keys as #8842 made it. The browser-facing one is read
|
|
450
|
+
through `lib/api-origin.generated.ts`'s `browserApiOrigin()` (#7874 D12):
|
|
451
|
+
`NEXT_PUBLIC_AILK_API_URL` on a hub, nothing on a spoke, which refuses that
|
|
452
|
+
name — so a spoke with `/pricing` passes its own `env:check` (#9480). The
|
|
453
|
+
magnet pages and the results permalink read it the same way.
|
|
430
454
|
- **A current shown set** — `lib/offerings-pricing.ts` maps it to a plans
|
|
431
455
|
fragment and an add-ons fragment. The first `pricing` section that is not
|
|
432
456
|
`addons` becomes the Stripe plans, and the first `addons` one the Stripe
|
|
@@ -546,7 +570,11 @@ A visitor's browser never calls the hub. Lead capture, newsletter signup, callba
|
|
|
546
570
|
- Don't reach into `apps/api` or `apps/mcp` from `apps/web`. They're peer apps — talk via HTTP/MCP.
|
|
547
571
|
- Don't commit images to `screenshots/` — only the `.gitkeep` is tracked.
|
|
548
572
|
|
|
549
|
-
Last updated: 2026-10-
|
|
573
|
+
Last updated: 2026-10-24 — § The `(auth)` route group: a magic link can create the account while sign-up is open, carrying the ticked agreements bound to its token (#9667) — verified against `lib/auth-email.ts`, `lib/sign-up-agreements.ts` and `app/[locale]/(auth)/sign-up/{page,sign-up-card}.tsx`.
|
|
574
|
+
|
|
575
|
+
Prior: 2026-10-21 — § Pricing page and § Magnet pages: `/pricing`, the magnet pages and the results permalink read the browser-facing API origin through `browserApiOrigin()` (#7874 D12), so a spoke that enables them passes its own `env:check` (#9480) — verified against `app/[locale]/pricing/page.tsx`, `app/[locale]/flows/[slug]/{magnet-page.tsx,results/[payload]/page.tsx}` and `lib/api-origin.generated.ts`.
|
|
576
|
+
|
|
577
|
+
Prior: 2026-10-20 — § Magnet pages: the trial magnet's pair, `/trial` (its button to `/trial/request` through `renderMagnetLanding`'s `startPath`) and the chrome-free `/trial/request` walk with its own `<h1>` fallback (#9287 C2, DD10) — verified against `app/[locale]/flows/[slug]/magnet-page.tsx`, `app/[locale]/trial/{page,request/page}.tsx` and `lib/magnet-routes.ts`.
|
|
550
578
|
|
|
551
579
|
Prior: 2026-10-19 — § Magnet pages: `/careers/apply` renders the contact email under its own `<h1>` when its flow is absent or the hub cannot answer; `readMagnet`'s `not-configured` kind 404s an unknown `/reports/<slug>` (and its `/start`) on a site with no hub to ask, while a configured hub that is down keeps #8848 D6's contact email (#9219) — verified against `app/[locale]/flows/[slug]/magnet-page.tsx`, `app/[locale]/careers/apply/page.tsx`, `app/[locale]/reports/deliverable-page.tsx` and `app/[locale]/reports/[slug]/{page,start/page}.tsx`.
|
|
552
580
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
* the surface disagreement `apps/mcp/__tests__/catalog-drift.test.ts` exists
|
|
17
17
|
* to make impossible. The same single read also yields the licence features
|
|
18
18
|
* the deployment holds (#7136), which gate the five `feature`-tagged tools
|
|
19
|
-
* here exactly as they gate registration on the MCP server.
|
|
19
|
+
* here exactly as they gate registration on the MCP server. `create_project`
|
|
20
|
+
* is left out while create-ailk's release scope holds the Free level (#9534),
|
|
21
|
+
* as `apps/mcp` leaves it unregistered — `lib/release-scope.ts`.
|
|
20
22
|
*
|
|
21
23
|
* Mirrors /.well-known/ai-plugin.json conventions: Response.json with a
|
|
22
24
|
* conservative cache-control header.
|
|
@@ -26,6 +28,7 @@
|
|
|
26
28
|
* is appropriate per the MCP discovery spec.
|
|
27
29
|
*/
|
|
28
30
|
|
|
31
|
+
import { isFreeLevelReleased } from "../../../lib/release-scope";
|
|
29
32
|
import { UNSERVED_MCP_TOOLS } from "../../../lib/topology.generated";
|
|
30
33
|
import packageJson from "../../../package.json";
|
|
31
34
|
import {
|
|
@@ -60,8 +63,11 @@ export async function GET(): Promise<Response> {
|
|
|
60
63
|
ailkVersion: packageJson.version,
|
|
61
64
|
commerceClaimed: heldFeatures.includes(COMMERCE_FEATURE),
|
|
62
65
|
heldFeatures,
|
|
63
|
-
// The tools this topology's MCP server does not register (#8070 D7)
|
|
64
|
-
|
|
66
|
+
// The tools this topology's MCP server does not register (#8070 D7) —
|
|
67
|
+
// and create_project while the Free level is held (#9534).
|
|
68
|
+
unservedTools: isFreeLevelReleased()
|
|
69
|
+
? UNSERVED_MCP_TOOLS
|
|
70
|
+
: [...UNSERVED_MCP_TOOLS, "create_project"],
|
|
65
71
|
// Spread conditional to satisfy exactOptionalPropertyTypes: omit the key
|
|
66
72
|
// entirely when the env var is not set rather than passing undefined.
|
|
67
73
|
...(mcpHttpUrlEnv ? { mcpHttpUrl: mcpHttpUrlEnv } : {}),
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* `next-intl/server` is mocked globally (apps/web/__tests__/setup.ts) against
|
|
18
18
|
* the real en.json, so the `auth` copy is asserted by its real strings.
|
|
19
19
|
*/
|
|
20
|
-
import { render, screen } from "@testing-library/react";
|
|
20
|
+
import { render, screen, within } from "@testing-library/react";
|
|
21
21
|
|
|
22
22
|
const mockGetActiveProviderIds = jest.fn();
|
|
23
23
|
const mockIsSignUpOpen = jest.fn();
|
|
@@ -217,12 +217,51 @@ describe("/sign-up follows isSignUpOpen()", () => {
|
|
|
217
217
|
it("renders the invitation intent when sign-up is closed", async () => {
|
|
218
218
|
mockIsSignUpOpen.mockReturnValue(false);
|
|
219
219
|
await renderPage(SignUpPage);
|
|
220
|
-
expect(screen.getByTestId("auth-invitation-body")).
|
|
220
|
+
expect(screen.getByTestId("auth-invitation-body")).toHaveTextContent(
|
|
221
|
+
en.auth.invitationBody,
|
|
222
|
+
);
|
|
221
223
|
expect(
|
|
222
|
-
screen.getByRole("heading", { name: en.auth.
|
|
224
|
+
screen.getByRole("heading", { name: en.auth.signUpHeading }),
|
|
223
225
|
).toBeInTheDocument();
|
|
224
226
|
expect(screen.queryByTestId("auth-submit")).not.toBeInTheDocument();
|
|
225
227
|
});
|
|
228
|
+
|
|
229
|
+
// The one card (#9662) frames both branches: the mark, "Sign up", the toggle
|
|
230
|
+
// line to /sign-in (no footer cross-link) and the acknowledgement.
|
|
231
|
+
it.each([
|
|
232
|
+
["closed", false],
|
|
233
|
+
["open", true],
|
|
234
|
+
] as const)("frames the %s card: mark, 'Sign up', toggle line, footnote (#9662)", async (_name, open) => {
|
|
235
|
+
mockIsSignUpOpen.mockReturnValue(open);
|
|
236
|
+
mockGetActiveProviderIds.mockReturnValue(["google", "email"]);
|
|
237
|
+
await renderPage(SignUpPage);
|
|
238
|
+
expect(screen.getByTestId("auth-card-logo")).toBeInTheDocument();
|
|
239
|
+
expect(screen.getByRole("heading", { name: "Sign up" })).toBeInTheDocument();
|
|
240
|
+
expect(screen.getByTestId("auth-card-prospect")).toHaveTextContent(
|
|
241
|
+
/^Already have an account\? Sign in$/,
|
|
242
|
+
);
|
|
243
|
+
expect(screen.getByTestId("auth-card-prospect-link")).toHaveAttribute(
|
|
244
|
+
"href",
|
|
245
|
+
"/sign-in",
|
|
246
|
+
);
|
|
247
|
+
expect(screen.queryByTestId("auth-footer-link")).not.toBeInTheDocument();
|
|
248
|
+
expect(screen.getByTestId("auth-card-footnote")).toHaveTextContent(
|
|
249
|
+
/^You acknowledge that you read, and agree to our Terms of Service and our Privacy Policy\.$/,
|
|
250
|
+
);
|
|
251
|
+
const footnote = within(screen.getByTestId("auth-card-footnote"));
|
|
252
|
+
expect(footnote.getByRole("link", { name: "Terms of Service" })).toHaveAttribute("href", "/terms");
|
|
253
|
+
expect(footnote.getByRole("link", { name: "Privacy Policy" })).toHaveAttribute("href", "/privacy");
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("offers 'or' + Google under the open card's form, with the consent checkboxes kept (#9662; #8438 D13)", async () => {
|
|
257
|
+
mockIsSignUpOpen.mockReturnValue(true);
|
|
258
|
+
mockGetActiveProviderIds.mockReturnValue(["google", "email"]);
|
|
259
|
+
await renderPage(SignUpPage);
|
|
260
|
+
expect(screen.getByLabelText("Email")).toBeInTheDocument();
|
|
261
|
+
expect(screen.getByTestId("auth-divider")).toHaveTextContent(/^or$/);
|
|
262
|
+
expect(screen.getByTestId("auth-social-google")).toBeInTheDocument();
|
|
263
|
+
expect(screen.getByTestId("sign-up-agreements")).toBeInTheDocument();
|
|
264
|
+
});
|
|
226
265
|
});
|
|
227
266
|
|
|
228
267
|
describe("/forgot-password and /reset-password follow the reset predicate", () => {
|
|
@@ -266,9 +305,9 @@ describe("/forgot-password and /reset-password follow the reset predicate", () =
|
|
|
266
305
|
|
|
267
306
|
// ── Every non-form page routes back to sign-in ───────────────────────────────
|
|
268
307
|
|
|
308
|
+
// A closed /sign-up routes back through its toggle line instead (#9662, above).
|
|
269
309
|
describe("the copy-only intents route back to sign-in", () => {
|
|
270
310
|
it.each([
|
|
271
|
-
["sign-up (closed)", SignUpPage],
|
|
272
311
|
["forgot-password (unavailable)", ForgotPasswordPage],
|
|
273
312
|
["reset-password (unavailable)", ResetPasswordPage],
|
|
274
313
|
["verify-email", VerifyEmailPage],
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The acknowledgement at the foot of every auth card (#8790 D6) — "You
|
|
3
|
+
* acknowledge that you read, and agree to our Terms of Service and our Privacy
|
|
4
|
+
* Policy." (#9662) — linking the site's own policy routes through the inline
|
|
5
|
+
* link variant, so the card never hardcodes a path.
|
|
6
|
+
*
|
|
7
|
+
* One builder for `/sign-in`, `/sign-up` and the `(authed)` gate.
|
|
8
|
+
* `caption` is the muted footnote role; a default `Text` would re-impose body
|
|
9
|
+
* size and the foreground colour over the card's footnote wrapper.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { localeHref } from "@working-theory/ui";
|
|
13
|
+
import { Link, Text } from "@working-theory/ui/primitives";
|
|
14
|
+
import type { ReactElement } from "react";
|
|
15
|
+
|
|
16
|
+
import type { SignInCardText } from "./sign-in/sign-in-text";
|
|
17
|
+
|
|
18
|
+
export function legalFootnote(
|
|
19
|
+
locale: string,
|
|
20
|
+
text: SignInCardText["acknowledgement"],
|
|
21
|
+
): ReactElement {
|
|
22
|
+
return (
|
|
23
|
+
<Text as="p" variant="caption">
|
|
24
|
+
{text.lead}{" "}
|
|
25
|
+
<Link variant="inline" href={localeHref(locale, "/terms")}>
|
|
26
|
+
{text.terms}
|
|
27
|
+
</Link>{" "}
|
|
28
|
+
{text.and}{" "}
|
|
29
|
+
<Link variant="inline" href={localeHref(locale, "/privacy")}>
|
|
30
|
+
{text.privacy}
|
|
31
|
+
</Link>
|
|
32
|
+
{text.end}
|
|
33
|
+
</Text>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -24,11 +24,16 @@
|
|
|
24
24
|
* (i) the hinted email (#8757 D9): a valid single `?email=` is the starting
|
|
25
25
|
* value of every email input of the card; an invalid or repeated value,
|
|
26
26
|
* or none, leaves them empty as before. It signs no one in.
|
|
27
|
+
* (j) the one card (#9662): the site's logo and "Sign in to <site>" from
|
|
28
|
+
* the deployment's own data — a crafted query parameter cannot change
|
|
29
|
+
* the name — the "Don't have an account? Sign up" line linking
|
|
30
|
+
* /sign-up, and the Terms + Privacy acknowledgement.
|
|
27
31
|
*
|
|
28
|
-
* `next-intl/server` is mocked
|
|
29
|
-
* the
|
|
32
|
+
* `next-intl/server` is mocked here against the real en.json, with `{name}`
|
|
33
|
+
* placeholders filled from the values passed, so `signIn` copy is asserted
|
|
34
|
+
* by its real strings and the heading by the name actually interpolated.
|
|
30
35
|
*/
|
|
31
|
-
import { render, screen } from "@testing-library/react";
|
|
36
|
+
import { render, screen, within } from "@testing-library/react";
|
|
32
37
|
import userEvent from "@testing-library/user-event";
|
|
33
38
|
|
|
34
39
|
const mockGetActiveProviderIds = jest.fn();
|
|
@@ -75,7 +80,31 @@ jest.mock("@working-theory/api-client", () => ({
|
|
|
75
80
|
__esModule: true,
|
|
76
81
|
hubSignIn: { clientInfo: (...args: unknown[]) => mockClientInfo(...args) },
|
|
77
82
|
}));
|
|
83
|
+
// The global shim (__tests__/__mocks__/next-intl-server.ts) returns messages
|
|
84
|
+
// uninterpolated; this suite fills `{name}` placeholders so the heading's
|
|
85
|
+
// organization name is the one the page actually passed (#9662).
|
|
86
|
+
jest.mock("next-intl/server", () => {
|
|
87
|
+
const messages = jest.requireActual("../../../../../messages/en.json") as Record<
|
|
88
|
+
string,
|
|
89
|
+
Record<string, string>
|
|
90
|
+
>;
|
|
91
|
+
return {
|
|
92
|
+
__esModule: true,
|
|
93
|
+
getTranslations: async ({ namespace }: { namespace: string }) => {
|
|
94
|
+
const catalog = messages[namespace];
|
|
95
|
+
const t = (key: string, values?: Record<string, string>): string =>
|
|
96
|
+
(catalog?.[key] ?? `${namespace}.${key}`).replace(
|
|
97
|
+
/\{(\w+)\}/g,
|
|
98
|
+
(match, name: string) => values?.[name] ?? match,
|
|
99
|
+
);
|
|
100
|
+
t.has = (key: string): boolean => catalog?.[key] !== undefined;
|
|
101
|
+
return t;
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
|
|
78
106
|
import { mintContinuation } from "../../../../api/auth/hub/continuation";
|
|
107
|
+
import { SITE_NAME } from "../../../../../lib/site-brand";
|
|
79
108
|
import en from "../../../../../messages/en.json";
|
|
80
109
|
import Page, { generateMetadata } from "../page";
|
|
81
110
|
|
|
@@ -119,7 +148,9 @@ describe("/sign-in page", () => {
|
|
|
119
148
|
expect(screen.queryByTestId("auth-submit")).toBeNull();
|
|
120
149
|
expect(screen.queryByTestId("auth-footer-link")).toBeNull();
|
|
121
150
|
expect(screen.queryByText(/create an account/i)).toBeNull();
|
|
122
|
-
expect(
|
|
151
|
+
expect(
|
|
152
|
+
screen.getByRole("heading", { name: `Sign in to ${SITE_NAME}` }),
|
|
153
|
+
).toBeInTheDocument();
|
|
123
154
|
});
|
|
124
155
|
|
|
125
156
|
it("(b) email + OAuth: password body with both social buttons, no sign-up footer", async () => {
|
|
@@ -241,7 +272,7 @@ describe("/sign-in page — the email sign-in link (#7435)", () => {
|
|
|
241
272
|
expect(screen.getByTestId("auth-submit")).toHaveTextContent(
|
|
242
273
|
en.signIn.emailLinkSubmit,
|
|
243
274
|
);
|
|
244
|
-
expect(en.signIn.emailLinkSubmit).toBe("
|
|
275
|
+
expect(en.signIn.emailLinkSubmit).toBe("Send me a magic link");
|
|
245
276
|
// One "or" divider between the primary and Google (#8790 D5).
|
|
246
277
|
expect(screen.getAllByTestId("auth-divider")).toHaveLength(1);
|
|
247
278
|
expect(screen.queryByTestId("auth-email-link-divider")).toBeNull();
|
|
@@ -252,9 +283,11 @@ describe("/sign-in page — the email sign-in link (#7435)", () => {
|
|
|
252
283
|
await renderPage();
|
|
253
284
|
expect(screen.getByTestId("auth-email")).toBeInTheDocument();
|
|
254
285
|
expect(screen.queryByText(en.signIn.notConfiguredSubhead)).toBeNull();
|
|
255
|
-
//
|
|
256
|
-
expect(
|
|
257
|
-
|
|
286
|
+
// The heading stands alone — no subhead (#8790 D3); #9662 names the site.
|
|
287
|
+
expect(
|
|
288
|
+
screen.getByRole("heading", { name: `Sign in to ${SITE_NAME}` }),
|
|
289
|
+
).toBeInTheDocument();
|
|
290
|
+
expect(en.signIn.heading).toBe("Sign in to {site}");
|
|
258
291
|
expect(screen.queryByTestId("auth-method-switch")).toBeNull();
|
|
259
292
|
});
|
|
260
293
|
|
|
@@ -415,3 +448,79 @@ describe("/sign-in page — the hinted email (#8757 D9)", () => {
|
|
|
415
448
|
},
|
|
416
449
|
);
|
|
417
450
|
});
|
|
451
|
+
|
|
452
|
+
describe("/sign-in page — the one card (#9662)", () => {
|
|
453
|
+
beforeEach(() => {
|
|
454
|
+
mockGetActiveProviderIds.mockReturnValue(["google", "email", "magic-link"]);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
it("(j) renders the site's logo and 'Sign in to <site>' from the deployment's data", async () => {
|
|
458
|
+
await renderPage("/account");
|
|
459
|
+
expect(screen.getByTestId("auth-card-logo")).toBeInTheDocument();
|
|
460
|
+
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
|
|
461
|
+
`Sign in to ${SITE_NAME}`,
|
|
462
|
+
);
|
|
463
|
+
expect(screen.getByLabelText(en.signIn.email)).toBe(
|
|
464
|
+
screen.getByTestId("auth-email"),
|
|
465
|
+
);
|
|
466
|
+
expect(en.signIn.email).toBe("Email");
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it("(j) a crafted query parameter cannot change the organization name", async () => {
|
|
470
|
+
const crafted = "Evil Corp";
|
|
471
|
+
expect(SITE_NAME).not.toBe(crafted);
|
|
472
|
+
const el = await Page({
|
|
473
|
+
params: Promise.resolve({ locale: "en" }),
|
|
474
|
+
searchParams: Promise.resolve({
|
|
475
|
+
next: `/account?site=${encodeURIComponent(crafted)}`,
|
|
476
|
+
site: crafted,
|
|
477
|
+
organization: crafted,
|
|
478
|
+
name: crafted,
|
|
479
|
+
siteName: crafted,
|
|
480
|
+
}),
|
|
481
|
+
});
|
|
482
|
+
render(el);
|
|
483
|
+
expect(screen.getByRole("heading", { level: 2 })).toHaveTextContent(
|
|
484
|
+
`Sign in to ${SITE_NAME}`,
|
|
485
|
+
);
|
|
486
|
+
expect(document.body.textContent).not.toContain(crafted);
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it("(j) the prospect line toggles to /sign-up, with no trailing period", async () => {
|
|
490
|
+
await renderPage("/account");
|
|
491
|
+
expect(screen.getByTestId("auth-card-prospect")).toHaveTextContent(
|
|
492
|
+
/^Don't have an account\? Sign up$/,
|
|
493
|
+
);
|
|
494
|
+
expect(screen.getByTestId("auth-card-prospect-link")).toHaveAttribute(
|
|
495
|
+
"href",
|
|
496
|
+
"/sign-up",
|
|
497
|
+
);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it("(j) 'Send me a magic link' first, the in-place password switch, then 'or' and Google", async () => {
|
|
501
|
+
await renderPage("/account");
|
|
502
|
+
expect(screen.getByTestId("auth-submit")).toHaveTextContent(
|
|
503
|
+
"Send me a magic link",
|
|
504
|
+
);
|
|
505
|
+
expect(screen.getByTestId("auth-method-switch")).toHaveTextContent(
|
|
506
|
+
"Sign in using password",
|
|
507
|
+
);
|
|
508
|
+
expect(screen.getByTestId("auth-divider")).toHaveTextContent(/^or$/);
|
|
509
|
+
expect(screen.getByTestId("auth-social-google")).toBeInTheDocument();
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it("(j) ends on the Terms of Service + Privacy Policy acknowledgement, linking the site's own routes", async () => {
|
|
513
|
+
await renderPage("/account");
|
|
514
|
+
const footnote = screen.getByTestId("auth-card-footnote");
|
|
515
|
+
expect(footnote).toHaveTextContent(
|
|
516
|
+
/^You acknowledge that you read, and agree to our Terms of Service and our Privacy Policy\.$/,
|
|
517
|
+
);
|
|
518
|
+
expect(
|
|
519
|
+
within(footnote).getByRole("link", { name: "Terms of Service" }),
|
|
520
|
+
).toHaveAttribute("href", "/terms");
|
|
521
|
+
expect(
|
|
522
|
+
within(footnote).getByRole("link", { name: "Privacy Policy" }),
|
|
523
|
+
).toHaveAttribute("href", "/privacy");
|
|
524
|
+
expect(within(footnote).getAllByRole("link")).toHaveLength(2);
|
|
525
|
+
});
|
|
526
|
+
});
|
|
@@ -18,14 +18,19 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Since #5963 the page lives in the `(auth)` route group — the URL is
|
|
20
20
|
* unchanged (a group contributes no path segment) but the frame is
|
|
21
|
-
* `AuthShell`, not the marketing Nav + Footer. The shell owns the
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* `AuthShell`, not the marketing Nav + Footer. The shell owns the 400px
|
|
22
|
+
* column; the card carries the site's mark (#8790 D3).
|
|
23
|
+
*
|
|
24
|
+
* The one card (#9662): "Sign in to <site>" (the name is the deployment's,
|
|
25
|
+
* read in `resolveSignInCardText`, never the request's), the "Don't have an
|
|
26
|
+
* account? Sign up" line to `/sign-up`, and the Terms + Privacy
|
|
27
|
+
* acknowledgement.
|
|
24
28
|
*
|
|
25
29
|
* Signed-in visitors are not redirected here — the Nav's session-aware action
|
|
26
30
|
* cluster (Account / Sign out) is the affordance for them.
|
|
27
31
|
*/
|
|
28
32
|
|
|
33
|
+
import { hubSignIn } from "@working-theory/api-client";
|
|
29
34
|
import { localeHref } from "@working-theory/ui";
|
|
30
35
|
import { accountEmailHintSchema } from "@working-theory/validation";
|
|
31
36
|
import type { Metadata } from "next";
|
|
@@ -36,14 +41,13 @@ import {
|
|
|
36
41
|
getActiveProviderIds,
|
|
37
42
|
resetSendConfigured,
|
|
38
43
|
} from "../../../../lib/auth-env";
|
|
39
|
-
|
|
40
|
-
import { hubSignIn } from "@working-theory/api-client";
|
|
41
|
-
import { Link, Text } from "@working-theory/ui/primitives";
|
|
42
44
|
import { siteLogo } from "../../../../lib/site-logo";
|
|
43
45
|
import {
|
|
44
46
|
CONTINUE_PATH,
|
|
45
47
|
openContinuation,
|
|
46
48
|
} from "../../../api/auth/hub/continuation";
|
|
49
|
+
import { legalFootnote } from "../legal-footnote";
|
|
50
|
+
|
|
47
51
|
import { resolveNextPath } from "./next-path";
|
|
48
52
|
import { SignInCard, type SignInProvider } from "./sign-in-card";
|
|
49
53
|
import { resolveSignInCardText, type SignInCardText } from "./sign-in-text";
|
|
@@ -151,27 +155,7 @@ export default async function SignInPage({
|
|
|
151
155
|
const defaultEmail = hintedEmail(rawEmail);
|
|
152
156
|
|
|
153
157
|
const spoke = await spokeFromNext(next);
|
|
154
|
-
|
|
155
|
-
// inline link variant; the card never hardcodes a path.
|
|
156
|
-
// `caption` is the muted footnote role; a default `Text` would re-impose
|
|
157
|
-
// body size and the foreground colour over the card's footnote wrapper.
|
|
158
|
-
const footnote = (
|
|
159
|
-
<Text as="p" variant="caption">
|
|
160
|
-
{text.acknowledgement.lead}{" "}
|
|
161
|
-
<Link variant="inline" href={localeHref(locale, "/terms")}>
|
|
162
|
-
{text.acknowledgement.terms}
|
|
163
|
-
</Link>
|
|
164
|
-
,{" "}
|
|
165
|
-
<Link variant="inline" href={localeHref(locale, "/privacy")}>
|
|
166
|
-
{text.acknowledgement.privacy}
|
|
167
|
-
</Link>
|
|
168
|
-
, and{" "}
|
|
169
|
-
<Link variant="inline" href={localeHref(locale, "/working-agreement")}>
|
|
170
|
-
{text.acknowledgement.workingAgreement}
|
|
171
|
-
</Link>
|
|
172
|
-
.
|
|
173
|
-
</Text>
|
|
174
|
-
);
|
|
158
|
+
const t = await getTranslations({ locale, namespace: "signIn" });
|
|
175
159
|
return (
|
|
176
160
|
<SignInCard
|
|
177
161
|
logo={siteLogo()}
|
|
@@ -179,19 +163,12 @@ export default async function SignInPage({
|
|
|
179
163
|
? {
|
|
180
164
|
backLink: {
|
|
181
165
|
href: `${spoke.origin}/account`,
|
|
182
|
-
label:
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
: {})}
|
|
186
|
-
{...(text.prospect
|
|
187
|
-
? {
|
|
188
|
-
prospect: {
|
|
189
|
-
...text.prospect,
|
|
190
|
-
href: localeHref(locale, "/sign-up"),
|
|
166
|
+
label: t("backTo", { site: spoke.name }),
|
|
191
167
|
},
|
|
192
168
|
}
|
|
193
169
|
: {})}
|
|
194
|
-
|
|
170
|
+
prospect={{ ...text.prospect, href: localeHref(locale, "/sign-up") }}
|
|
171
|
+
footnote={legalFootnote(locale, text.acknowledgement)}
|
|
195
172
|
providers={providers}
|
|
196
173
|
method={method}
|
|
197
174
|
next={next}
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
* method from auth-env and hands them in; this component never reads env
|
|
12
12
|
* itself.
|
|
13
13
|
*
|
|
14
|
-
* The
|
|
15
|
-
*
|
|
14
|
+
* The site's mark arrives as `logo` (#8790 D3) and renders centred in the
|
|
15
|
+
* card; the shell draws no brand row.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* `footer="none"` drops AuthCard's "Not a member? Create an account"
|
|
18
|
+
* cross-link; the page's `prospect` line ("Don't have an account? Sign up",
|
|
19
|
+
* #9662) is the one route to `/sign-up`.
|
|
20
20
|
*
|
|
21
21
|
* Password path: `apps/web/auth.ts` does not enable `emailAndPassword` today,
|
|
22
22
|
* so `signIn.email` is wired but inert (Better Auth answers with an error)
|
|
@@ -242,7 +242,7 @@ export function SignInCard({
|
|
|
242
242
|
{...(logo !== undefined ? { logo } : {})}
|
|
243
243
|
{...(forgotHref !== undefined ? { forgotHref } : {})}
|
|
244
244
|
{...(forgot !== undefined ? { forgot } : {})}
|
|
245
|
-
//
|
|
245
|
+
// The heading stands alone (#8790 D3): no subhead unless the card
|
|
246
246
|
// is inert and must say why.
|
|
247
247
|
subhead={notConfigured ? notConfiguredSubhead : ""}
|
|
248
248
|
{...(prospect !== undefined ? { prospect } : {})}
|