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,4 +1,4 @@
|
|
|
1
|
-
"use client"; // Better Auth's client calls (signUp.email / signIn.social) + error state
|
|
1
|
+
"use client"; // Better Auth's client calls (signUp.email / signIn.social / $fetch) + error state
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* SignUpCard — the /sign-up page's client island (#5963).
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
* documented posture the sign-in island already carries for its password
|
|
14
14
|
* path. The page only renders this island at all when `isSignUpOpen()`.
|
|
15
15
|
*
|
|
16
|
-
* The
|
|
16
|
+
* The one card (#9662): the page hands in the site's mark (`logo`), the
|
|
17
|
+
* "Already have an account? Sign in" line (`prospect`, in place of AuthCard's
|
|
18
|
+
* footer cross-link) and the Terms + Privacy acknowledgement (`footnote`).
|
|
19
|
+
* The heading stands alone — no subhead unless the card is inert.
|
|
17
20
|
*
|
|
18
21
|
* Error surface: `AuthCard`'s `errors` prop is per-field, so a failed provider
|
|
19
22
|
* launch lands on `errors.email` (the social row sits inside the password form
|
|
@@ -37,6 +40,14 @@
|
|
|
37
40
|
* `additionalData`, which Better Auth keeps in the OAuth state for the
|
|
38
41
|
* callback. The server writes the grants with the user
|
|
39
42
|
* (`lib/sign-up-agreements.ts`); no cookie carries them.
|
|
43
|
+
*
|
|
44
|
+
* #9667 D6 — the magic-link method. With the email sign-in link on, the card
|
|
45
|
+
* is AuthCard's one-field "Send me a magic link" body, gated the same way.
|
|
46
|
+
* The request goes through the shared client's `$fetch`, never the
|
|
47
|
+
* `magicLinkClient()` plugin (for the reason `sign-in-card.tsx` records), with
|
|
48
|
+
* the agreements and locale in its `metadata` — which is what makes it a
|
|
49
|
+
* sign-up request. The server binds them to the token and creates the account
|
|
50
|
+
* on verify. The sent state never says whether the address had an account.
|
|
40
51
|
*/
|
|
41
52
|
|
|
42
53
|
import {
|
|
@@ -47,7 +58,13 @@ import {
|
|
|
47
58
|
} from "@working-theory/ui/blocks";
|
|
48
59
|
import { Alert, AlertDescription } from "@working-theory/ui/primitives";
|
|
49
60
|
import { SIGN_UP_AGREEMENTS_FIELD } from "@working-theory/validation";
|
|
50
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
useRef,
|
|
63
|
+
useState,
|
|
64
|
+
type MouseEvent,
|
|
65
|
+
type ReactElement,
|
|
66
|
+
type ReactNode,
|
|
67
|
+
} from "react";
|
|
51
68
|
|
|
52
69
|
import { authClient, useAuthCardFlow } from "../use-auth-card-flow";
|
|
53
70
|
|
|
@@ -62,17 +79,35 @@ export interface SignUpAgreement {
|
|
|
62
79
|
statement: string;
|
|
63
80
|
}
|
|
64
81
|
|
|
82
|
+
/** Translated copy for the magic-link sign-up (#9667 D6). */
|
|
83
|
+
export interface SignUpLinkLabels {
|
|
84
|
+
sentHeading: string;
|
|
85
|
+
sentSubhead: string;
|
|
86
|
+
sentBody: string;
|
|
87
|
+
/** The sent state's "Back to sign up" link. */
|
|
88
|
+
back: string;
|
|
89
|
+
/** Any failed request other than a rate limit or the agreements. */
|
|
90
|
+
failed: string;
|
|
91
|
+
/** A 429 from Better Auth's per-IP limit. */
|
|
92
|
+
rateLimited: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
65
95
|
export interface SignUpCardProps {
|
|
66
96
|
/** The site's mark, centred in the card at 48px (#8790 D3). */
|
|
67
97
|
logo?: ReactNode;
|
|
68
98
|
/** Active OAuth providers, exactly as auth-env reports them. */
|
|
69
99
|
providers: SignUpProvider[];
|
|
70
|
-
/**
|
|
71
|
-
|
|
100
|
+
/**
|
|
101
|
+
* "magic-link" when the email sign-in link is active, else "password" when
|
|
102
|
+
* the email provider is, otherwise "sso".
|
|
103
|
+
*/
|
|
104
|
+
method: "sso" | "password" | "magic-link";
|
|
72
105
|
/** Post-sign-up path. */
|
|
73
106
|
next: string;
|
|
74
|
-
/**
|
|
75
|
-
|
|
107
|
+
/** The "Already have an account? Sign in" line to /sign-in (#9662). */
|
|
108
|
+
prospect: { prompt: string; linkLabel: string; href: string };
|
|
109
|
+
/** The acknowledgement sentence(s) at the card's foot (#9662). */
|
|
110
|
+
footnote: ReactNode;
|
|
76
111
|
/** Translated AuthCard labels (resolved server-side by the page). */
|
|
77
112
|
labels: AuthCardLabels;
|
|
78
113
|
/** Subhead shown when no provider is configured. */
|
|
@@ -92,6 +127,12 @@ export interface SignUpCardProps {
|
|
|
92
127
|
agreementsLegend: string;
|
|
93
128
|
/** The page's locale, sent with the agreements (the statements' language). */
|
|
94
129
|
locale: string;
|
|
130
|
+
/** Where a failed link lands (`/sign-up`); Better Auth appends `?error`. */
|
|
131
|
+
errorCallbackURL?: string;
|
|
132
|
+
/** Fixed copy for a failed link (`?error=` mapped by the page), shown above the card. */
|
|
133
|
+
linkNotice?: string;
|
|
134
|
+
/** The magic-link method's copy; required when `method` is "magic-link". */
|
|
135
|
+
linkLabels?: SignUpLinkLabels;
|
|
95
136
|
}
|
|
96
137
|
|
|
97
138
|
/** The server's body key for the ticked ids — also the group's control name. */
|
|
@@ -112,7 +153,8 @@ export function SignUpCard({
|
|
|
112
153
|
providers,
|
|
113
154
|
method,
|
|
114
155
|
next,
|
|
115
|
-
|
|
156
|
+
prospect,
|
|
157
|
+
footnote,
|
|
116
158
|
labels,
|
|
117
159
|
notConfiguredSubhead,
|
|
118
160
|
errorLabels,
|
|
@@ -121,6 +163,9 @@ export function SignUpCard({
|
|
|
121
163
|
agreementsLegend,
|
|
122
164
|
logo,
|
|
123
165
|
locale,
|
|
166
|
+
errorCallbackURL,
|
|
167
|
+
linkNotice,
|
|
168
|
+
linkLabels,
|
|
124
169
|
}: SignUpCardProps): ReactElement {
|
|
125
170
|
const { errors, providerError, launchProvider, submitPassword } =
|
|
126
171
|
useAuthCardFlow(next, {
|
|
@@ -135,6 +180,11 @@ export function SignUpCard({
|
|
|
135
180
|
const [agreementsError, setAgreementsError] = useState<string | undefined>(
|
|
136
181
|
undefined,
|
|
137
182
|
);
|
|
183
|
+
const [linkSent, setLinkSent] = useState(false);
|
|
184
|
+
const [linkError, setLinkError] = useState<string | undefined>(undefined);
|
|
185
|
+
// One request at a time: a double-click would spend two of the per-IP
|
|
186
|
+
// sends and mint two live tokens (as sign-in-card.tsx).
|
|
187
|
+
const linkPending = useRef(false);
|
|
138
188
|
const allAgreed = requiredAgreementIds.every((id) => ticked.has(id));
|
|
139
189
|
// What the server checks and records (D10): the ticked ids, in the order shown.
|
|
140
190
|
const agreed = (): { agreements: string[]; locale: string } => ({
|
|
@@ -201,8 +251,72 @@ export function SignUpCard({
|
|
|
201
251
|
);
|
|
202
252
|
};
|
|
203
253
|
|
|
254
|
+
const requestSignUpLink = async (email: string): Promise<void> => {
|
|
255
|
+
if (!allAgreed || linkPending.current) return;
|
|
256
|
+
linkPending.current = true;
|
|
257
|
+
setAgreementsError(undefined);
|
|
258
|
+
setLinkError(undefined);
|
|
259
|
+
try {
|
|
260
|
+
const { error } = await authClient.$fetch("/sign-in/magic-link", {
|
|
261
|
+
method: "POST",
|
|
262
|
+
body: {
|
|
263
|
+
email,
|
|
264
|
+
// As the password submit: Better Auth wants a name on a new user.
|
|
265
|
+
name: email,
|
|
266
|
+
callbackURL: next,
|
|
267
|
+
errorCallbackURL,
|
|
268
|
+
metadata: agreed(),
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
if (!error) {
|
|
272
|
+
setLinkSent(true);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (errorCode({ error }) === AGREEMENTS_REQUIRED) {
|
|
276
|
+
setAgreementsError(errorLabels.agreementsRequired);
|
|
277
|
+
} else {
|
|
278
|
+
setLinkError(
|
|
279
|
+
error.status === 429 ? linkLabels?.rateLimited : linkLabels?.failed,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
} catch {
|
|
283
|
+
setLinkError(linkLabels?.failed);
|
|
284
|
+
} finally {
|
|
285
|
+
linkPending.current = false;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
if (method === "magic-link" && linkSent && linkLabels) {
|
|
290
|
+
// No `sentTo`: both a new and a taken address get a link, and the state
|
|
291
|
+
// must not say which.
|
|
292
|
+
return (
|
|
293
|
+
<div className="flex flex-col gap-4" data-testid="sign-up-page">
|
|
294
|
+
<AuthCard
|
|
295
|
+
{...(logo !== undefined ? { logo } : {})}
|
|
296
|
+
intent="sent"
|
|
297
|
+
footer="cross-link"
|
|
298
|
+
// "Back to sign up": this page, where a failed link also lands.
|
|
299
|
+
{...(errorCallbackURL !== undefined
|
|
300
|
+
? { signInHref: errorCallbackURL }
|
|
301
|
+
: {})}
|
|
302
|
+
labels={{
|
|
303
|
+
sentHeading: linkLabels.sentHeading,
|
|
304
|
+
sentSubhead: linkLabels.sentSubhead,
|
|
305
|
+
sentBody: linkLabels.sentBody,
|
|
306
|
+
backToSignIn: linkLabels.back,
|
|
307
|
+
}}
|
|
308
|
+
/>
|
|
309
|
+
</div>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
204
313
|
return (
|
|
205
314
|
<div className="flex flex-col gap-4" data-testid="sign-up-page">
|
|
315
|
+
{linkNotice ? (
|
|
316
|
+
<Alert variant="error" data-testid="sign-up-link-notice">
|
|
317
|
+
<AlertDescription>{linkNotice}</AlertDescription>
|
|
318
|
+
</Alert>
|
|
319
|
+
) : null}
|
|
206
320
|
{method === "sso" && providerError ? (
|
|
207
321
|
<Alert variant="error" data-testid="sign-up-provider-error">
|
|
208
322
|
<AlertDescription>{providerError}</AlertDescription>
|
|
@@ -217,11 +331,17 @@ export function SignUpCard({
|
|
|
217
331
|
{...(logo !== undefined ? { logo } : {})}
|
|
218
332
|
intent="sign-up"
|
|
219
333
|
method={method}
|
|
220
|
-
|
|
221
|
-
{
|
|
334
|
+
footer="none"
|
|
335
|
+
subhead={notConfigured ? notConfiguredSubhead : ""}
|
|
336
|
+
prospect={prospect}
|
|
337
|
+
footnote={footnote}
|
|
222
338
|
providers={providerButtons}
|
|
223
|
-
onSubmit={
|
|
224
|
-
|
|
339
|
+
onSubmit={
|
|
340
|
+
method === "magic-link"
|
|
341
|
+
? (data) => void requestSignUpLink(data.email)
|
|
342
|
+
: handleSubmit
|
|
343
|
+
}
|
|
344
|
+
errors={linkError ? { ...errors, email: linkError } : errors}
|
|
225
345
|
labels={labels}
|
|
226
346
|
/>
|
|
227
347
|
</div>
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* 9. On an account path (#7430) the gate speaks to members — the
|
|
20
20
|
* `account.gate` copy, never `waitlistDashboard.gate` — and its
|
|
21
21
|
* not-configured headline is a real heading element.
|
|
22
|
+
* 10. The member gate renders the one card (#9662): `/sign-in`'s card with
|
|
23
|
+
* the site's mark, the toggle line to /sign-up and the Terms + Privacy
|
|
24
|
+
* acknowledgement.
|
|
22
25
|
*/
|
|
23
26
|
import { readFileSync } from "node:fs";
|
|
24
27
|
import { join } from "node:path";
|
|
@@ -407,13 +410,62 @@ describe("AuthedLayout — the signed-out gate on an account path (#7430)", () =
|
|
|
407
410
|
await renderSignedOutLayout();
|
|
408
411
|
expect(gateNamespaces()).toContain("account.gate");
|
|
409
412
|
expect(gateNamespaces()).not.toContain("waitlistDashboard.gate");
|
|
410
|
-
expect(screen.getByTestId("auth-
|
|
413
|
+
expect(screen.getByTestId("auth-sso-google")).toBeInTheDocument();
|
|
411
414
|
expect(screen.getByTestId("sign-in-gate-link")).toHaveAttribute(
|
|
412
415
|
"href",
|
|
413
416
|
"/sign-in?next=%2Faccount",
|
|
414
417
|
);
|
|
415
418
|
});
|
|
416
419
|
|
|
420
|
+
// A client component's props cross the RSC boundary: React refuses a
|
|
421
|
+
// function there, so the card's copy must arrive as plain data (#9662 —
|
|
422
|
+
// the 500 a function-valued `backTo` once caused here).
|
|
423
|
+
it.each([
|
|
424
|
+
["Google", false],
|
|
425
|
+
["Google + the email link", true],
|
|
426
|
+
] as const)("hands SignInGate no function in its card props (%s)", async (_name, withEmailLink) => {
|
|
427
|
+
configureGoogle();
|
|
428
|
+
if (withEmailLink) configureEmailLink();
|
|
429
|
+
mockGetSession.mockResolvedValue(null);
|
|
430
|
+
const element = (await AuthedLayout({
|
|
431
|
+
params: Promise.resolve({ locale: "en" }),
|
|
432
|
+
children: <div />,
|
|
433
|
+
})) as React.ReactElement<{ card?: { text: Record<string, unknown> } }>;
|
|
434
|
+
const text = element.props.card?.text;
|
|
435
|
+
expect(text).toBeDefined();
|
|
436
|
+
const functions = Object.entries(text ?? {}).filter(
|
|
437
|
+
([, value]) => typeof value === "function",
|
|
438
|
+
);
|
|
439
|
+
expect(functions).toEqual([]);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it.each([
|
|
443
|
+
["Google", false],
|
|
444
|
+
["Google + the email link", true],
|
|
445
|
+
] as const)("renders the one card with %s: the mark, the toggle line and the acknowledgement (#9662)", async (_name, withEmailLink) => {
|
|
446
|
+
configureGoogle();
|
|
447
|
+
if (withEmailLink) configureEmailLink();
|
|
448
|
+
await renderSignedOutLayout();
|
|
449
|
+
expect(screen.getByTestId("sign-in-page")).toBeInTheDocument();
|
|
450
|
+
expect(screen.queryByTestId("auth-panel-card")).not.toBeInTheDocument();
|
|
451
|
+
expect(screen.getByTestId("auth-card-logo")).toBeInTheDocument();
|
|
452
|
+
expect(screen.getByTestId("auth-card-prospect-link")).toHaveAttribute(
|
|
453
|
+
"href",
|
|
454
|
+
"/sign-up",
|
|
455
|
+
);
|
|
456
|
+
const footnote = screen.getByTestId("auth-card-footnote");
|
|
457
|
+
expect(footnote.querySelector('a[href="/terms"]')).not.toBeNull();
|
|
458
|
+
expect(footnote.querySelector('a[href="/privacy"]')).not.toBeNull();
|
|
459
|
+
if (withEmailLink) {
|
|
460
|
+
expect(screen.getByTestId("auth-submit")).toHaveTextContent(
|
|
461
|
+
"copy:emailLinkSubmit",
|
|
462
|
+
);
|
|
463
|
+
expect(screen.getByTestId("auth-social-google")).toBeInTheDocument();
|
|
464
|
+
} else {
|
|
465
|
+
expect(screen.queryByTestId("auth-email")).not.toBeInTheDocument();
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
417
469
|
it("renders the not-configured headline as a real heading, not a <p>", async () => {
|
|
418
470
|
await renderSignedOutLayout();
|
|
419
471
|
expect(gateNamespaces()).toContain("account.gate");
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
* button; (d) a 500 or a throw shows the error row, never "no
|
|
11
11
|
* subscription"; (e) a contributed billing section renders after every
|
|
12
12
|
* one of these; (f) the read asks for `include: "billing"`.
|
|
13
|
+
* #9401 AC-9 (spec docs/specs/9401-show-a-buyer-s-ailk-spec.md D7): a
|
|
14
|
+
* section the site adds to `siteBillingSections` renders after the
|
|
15
|
+
* modules' `accountBillingSections`, each under its `ctx.t(title)`.
|
|
13
16
|
* #8217 AC-1 (spec docs/specs/8217-spoke-billing-spoke-checkout-reads-spec.md
|
|
14
17
|
* D10, D11): `openBillingPortal()` mints the portal through
|
|
15
18
|
* `billingPortalUrl()` — the hub's route, once, with the cookie init — and
|
|
@@ -81,6 +84,7 @@ jest.mock("next/navigation", () => ({
|
|
|
81
84
|
import type { AccountBillingSection } from "@working-theory/templates/account";
|
|
82
85
|
|
|
83
86
|
import { accountBillingSections } from "../../../../../lib/account-config";
|
|
87
|
+
import { siteBillingSections } from "../../../../../lib/site-contributions";
|
|
84
88
|
import { openBillingPortal } from "../actions";
|
|
85
89
|
|
|
86
90
|
// The Billing route's own page, loaded with `import()`: architecture.yaml bans
|
|
@@ -276,6 +280,40 @@ describe("AC-2 (e) — contributed billing sections render after the base conten
|
|
|
276
280
|
});
|
|
277
281
|
});
|
|
278
282
|
|
|
283
|
+
describe("#9401 AC-9 — a site's own section renders after the modules' (D7)", () => {
|
|
284
|
+
const moduleSection: AccountBillingSection = {
|
|
285
|
+
id: "module",
|
|
286
|
+
title: "settings.billing.currentPlan",
|
|
287
|
+
render: () => <p data-testid="module-body">Module</p>,
|
|
288
|
+
};
|
|
289
|
+
const siteSection: AccountBillingSection = {
|
|
290
|
+
id: "site",
|
|
291
|
+
title: "settings.billing.title",
|
|
292
|
+
render: () => <p data-testid="site-body">Site</p>,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
beforeAll(() => {
|
|
296
|
+
accountBillingSections.push(moduleSection);
|
|
297
|
+
siteBillingSections.push(siteSection);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
afterAll(() => {
|
|
301
|
+
accountBillingSections.splice(accountBillingSections.indexOf(moduleSection), 1);
|
|
302
|
+
siteBillingSections.splice(siteBillingSections.indexOf(siteSection), 1);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("renders the module's section, then the site's, each under its translated title", async () => {
|
|
306
|
+
await renderPage();
|
|
307
|
+
const contributed = screen.getByTestId("account-settings-module");
|
|
308
|
+
const site = screen.getByTestId("account-settings-site");
|
|
309
|
+
expect(within(contributed).getByTestId("module-body")).toBeInTheDocument();
|
|
310
|
+
expect(within(site).getByTestId("site-body")).toBeInTheDocument();
|
|
311
|
+
expect(within(contributed).getByRole("heading", { level: 2 })).toHaveTextContent("Current plan");
|
|
312
|
+
expect(within(site).getByRole("heading", { level: 2 })).toHaveTextContent("Billing");
|
|
313
|
+
expect(contributed.compareDocumentPosition(site) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
279
317
|
describe("#8217 AC-1 — the single site's Manage billing (D10, D11)", () => {
|
|
280
318
|
const PORTAL_URL = "https://billing.stripe.com/p/session/test_single_site";
|
|
281
319
|
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
*
|
|
20
20
|
* After any of the three, one plain line when some of the member's billing
|
|
21
21
|
* is on a Stripe account this spoke's key cannot read (#8217 D12), then
|
|
22
|
-
* each section a module contributes (`accountBillingSections`, #8231 D4)
|
|
22
|
+
* each section a module contributes (`accountBillingSections`, #8231 D4),
|
|
23
|
+
* then each section the site adds (`siteBillingSections`, #9401 D7).
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
26
|
import { AccountSettingsFrame, AccountSettingsPane, CurrentPlanCard } from "@working-theory/templates/account";
|
|
@@ -29,6 +30,7 @@ import { getTranslations } from "next-intl/server";
|
|
|
29
30
|
import type { ReactElement } from "react";
|
|
30
31
|
|
|
31
32
|
import { accountBillingSections } from "../../../../../lib/account-config";
|
|
33
|
+
import { siteBillingSections } from "../../../../../lib/site-contributions";
|
|
32
34
|
import { accountSession } from "../account-data";
|
|
33
35
|
import { openBillingPortal } from "../actions";
|
|
34
36
|
import { type BillingState, loadBilling } from "../billing-source";
|
|
@@ -161,7 +163,7 @@ export default async function AccountBillingPage({ params }: Props): Promise<Rea
|
|
|
161
163
|
</div>
|
|
162
164
|
) : null}
|
|
163
165
|
|
|
164
|
-
{accountBillingSections.map((section) => (
|
|
166
|
+
{[...accountBillingSections, ...siteBillingSections].map((section) => (
|
|
165
167
|
<SettingsSection key={section.id} id={section.id} title={ctx.t(section.title)}>
|
|
166
168
|
{section.render(ctx)}
|
|
167
169
|
</SettingsSection>
|
|
@@ -20,18 +20,23 @@
|
|
|
20
20
|
* current pathname (via `usePathname()`) so a successful social sign-in
|
|
21
21
|
* lands back on the exact dashboard page the visitor requested.
|
|
22
22
|
*
|
|
23
|
-
* Email sign-in link (#7435 § D9): when the layout passes `
|
|
24
|
-
* gate renders `/sign-in`'s own `SignInCard` — the same
|
|
25
|
-
* me a
|
|
26
|
-
* has no submit wiring and would otherwise sit inert
|
|
27
|
-
* Without the prop every render is what it was before.
|
|
23
|
+
* Email sign-in link (#7435 § D9): when the layout passes `card` with
|
|
24
|
+
* `emailLink`, the gate renders `/sign-in`'s own `SignInCard` — the same
|
|
25
|
+
* providers plus "Send me a magic link" — in place of `AuthPanel`, whose
|
|
26
|
+
* email + password form has no submit wiring and would otherwise sit inert
|
|
27
|
+
* beside the new field. Without the prop every render is what it was before.
|
|
28
|
+
*
|
|
29
|
+
* The one card (#9662): on the member `/account` gate the layout passes
|
|
30
|
+
* `card` whenever a method is on, with the site's mark, the "Don't have an
|
|
31
|
+
* account? Sign up" line and the Terms + Privacy acknowledgement, so the gate
|
|
32
|
+
* renders the same card `/sign-in` does.
|
|
28
33
|
*/
|
|
29
34
|
|
|
30
35
|
import { EmptyState, Link } from "@working-theory/ui/primitives";
|
|
31
36
|
import { AuthPanel, type AuthPanelProvider } from "@working-theory/ui/sections";
|
|
32
37
|
import { createAuthClient } from "better-auth/react";
|
|
33
38
|
import { usePathname } from "next/navigation";
|
|
34
|
-
import type { ReactElement } from "react";
|
|
39
|
+
import type { ReactElement, ReactNode } from "react";
|
|
35
40
|
|
|
36
41
|
import { SignInCard } from "../(auth)/sign-in/sign-in-card";
|
|
37
42
|
import type { SignInCardText } from "../(auth)/sign-in/sign-in-text";
|
|
@@ -52,17 +57,25 @@ export interface SignInGateProps {
|
|
|
52
57
|
/** The active social providers, resolved server-side by the layout (#7419). */
|
|
53
58
|
providers: AuthPanelProvider[];
|
|
54
59
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
60
|
+
* Renders `SignInCard` in place of `AuthPanel` — present when the email
|
|
61
|
+
* sign-in link is on (#7435) or on the member gate (#9662). The card's copy,
|
|
62
|
+
* mark, prospect line and footnote are resolved server-side by the layout.
|
|
57
63
|
*/
|
|
58
|
-
|
|
64
|
+
card?: {
|
|
65
|
+
text: SignInCardText;
|
|
66
|
+
/** Offer "Send me a magic link" — the email sign-in link is on. */
|
|
67
|
+
emailLink: boolean;
|
|
68
|
+
logo?: ReactNode;
|
|
69
|
+
prospect?: { prompt: string; linkLabel: string; href: string };
|
|
70
|
+
footnote?: ReactNode;
|
|
71
|
+
};
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
export function SignInGate({
|
|
62
75
|
labels,
|
|
63
76
|
signInPath,
|
|
64
77
|
providers,
|
|
65
|
-
|
|
78
|
+
card,
|
|
66
79
|
}: SignInGateProps): ReactElement {
|
|
67
80
|
const pathname = usePathname();
|
|
68
81
|
const signInHref = `${signInPath}?next=${encodeURIComponent(pathname)}`;
|
|
@@ -79,25 +92,35 @@ export function SignInGate({
|
|
|
79
92
|
</Link>
|
|
80
93
|
);
|
|
81
94
|
|
|
82
|
-
if (
|
|
83
|
-
const { text } =
|
|
95
|
+
if (card) {
|
|
96
|
+
const { text } = card;
|
|
84
97
|
return (
|
|
85
98
|
<div
|
|
86
99
|
className="flex min-h-screen flex-col items-center justify-center gap-4 py-section"
|
|
87
100
|
data-testid="sign-in-gate"
|
|
88
101
|
>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
{/* AuthShell's 400px column: the cap sits on the wrapper, never on the card (AuthShell.tsx). */}
|
|
103
|
+
<div className="w-full max-w-100">
|
|
104
|
+
<SignInCard
|
|
105
|
+
providers={providers}
|
|
106
|
+
method="sso"
|
|
107
|
+
next={pathname}
|
|
108
|
+
labels={text.labels}
|
|
109
|
+
notConfiguredSubhead={text.notConfiguredSubhead}
|
|
110
|
+
errorLabels={text.errorLabels}
|
|
111
|
+
emailLink={card.emailLink}
|
|
112
|
+
errorCallbackURL={signInHref}
|
|
113
|
+
signInHref={signInHref}
|
|
114
|
+
emailLinkLabels={text.emailLinkLabels}
|
|
115
|
+
{...(card.logo !== undefined ? { logo: card.logo } : {})}
|
|
116
|
+
{...(card.prospect !== undefined
|
|
117
|
+
? { prospect: card.prospect }
|
|
118
|
+
: {})}
|
|
119
|
+
{...(card.footnote !== undefined
|
|
120
|
+
? { footnote: card.footnote }
|
|
121
|
+
: {})}
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
101
124
|
{signInLink}
|
|
102
125
|
</div>
|
|
103
126
|
);
|
|
@@ -11,9 +11,11 @@ import { readLocales } from "@working-theory/web-i18n";
|
|
|
11
11
|
import { getTranslations } from "next-intl/server";
|
|
12
12
|
import type { ReactElement } from "react";
|
|
13
13
|
|
|
14
|
+
import { legalFootnote } from "../(auth)/legal-footnote";
|
|
14
15
|
import { resolveSignInCardText } from "../(auth)/sign-in/sign-in-text";
|
|
15
16
|
import { getActiveProviderIds } from "../../../lib/auth-env";
|
|
16
17
|
import { isAccountPath } from "../../../lib/auth-routes";
|
|
18
|
+
import { siteLogo } from "../../../lib/site-logo";
|
|
17
19
|
|
|
18
20
|
import { SignInGate } from "./sign-in-gate";
|
|
19
21
|
|
|
@@ -39,9 +41,7 @@ export async function SignedOutGate({
|
|
|
39
41
|
namespace: isAccount ? "account.gate" : "waitlistDashboard.gate",
|
|
40
42
|
});
|
|
41
43
|
const active = getActiveProviderIds();
|
|
42
|
-
const emailLink = active.includes("magic-link")
|
|
43
|
-
? { text: await resolveSignInCardText(locale) }
|
|
44
|
-
: undefined;
|
|
44
|
+
const emailLink = active.includes("magic-link");
|
|
45
45
|
const providers = active.filter((id): id is AuthPanelProvider =>
|
|
46
46
|
(SUPPORTED_PROVIDERS as readonly string[]).includes(id),
|
|
47
47
|
);
|
|
@@ -75,6 +75,25 @@ export async function SignedOutGate({
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// The sign-in card: with the email link on, and on the member gate, which
|
|
79
|
+
// also wears the one card's frame — the mark, the toggle line to /sign-up
|
|
80
|
+
// and the Terms + Privacy acknowledgement (#9662).
|
|
81
|
+
const text =
|
|
82
|
+
emailLink || isAccount ? await resolveSignInCardText(locale) : undefined;
|
|
83
|
+
const card = text
|
|
84
|
+
? {
|
|
85
|
+
text,
|
|
86
|
+
emailLink,
|
|
87
|
+
...(isAccount
|
|
88
|
+
? {
|
|
89
|
+
logo: siteLogo(),
|
|
90
|
+
prospect: { ...text.prospect, href: localeHref(locale, "/sign-up") },
|
|
91
|
+
footnote: legalFootnote(locale, text.acknowledgement),
|
|
92
|
+
}
|
|
93
|
+
: {}),
|
|
94
|
+
}
|
|
95
|
+
: undefined;
|
|
96
|
+
|
|
78
97
|
return (
|
|
79
98
|
<SignInGate
|
|
80
99
|
labels={{
|
|
@@ -84,7 +103,7 @@ export async function SignedOutGate({
|
|
|
84
103
|
}}
|
|
85
104
|
signInPath={signInPath}
|
|
86
105
|
providers={providers}
|
|
87
|
-
{...(
|
|
106
|
+
{...(card ? { card } : {})}
|
|
88
107
|
/>
|
|
89
108
|
);
|
|
90
109
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ConversationalIntakeWrapper (#4534, epic #4521's integration leg).
|
|
6
6
|
*
|
|
7
7
|
* `recordIntakeTurn` fires `track()` (`@working-theory/analytics/server`,
|
|
8
|
-
* the same fire-and-forget helper `
|
|
8
|
+
* the same fire-and-forget helper `packages/api/src/routes/leads/index.ts`
|
|
9
9
|
* already uses for "lead-captured") once per conversation turn, tagged with
|
|
10
10
|
* the turn index and the engine status as of that turn. A session's last
|
|
11
11
|
* "intake-turn-abandonment" event with `status: "in_progress"` marks the
|
|
@@ -86,6 +86,7 @@ jest.mock("../../../contact/site-contact-email", () => ({
|
|
|
86
86
|
readSiteContactEmail: () => "hello@example.com",
|
|
87
87
|
}));
|
|
88
88
|
|
|
89
|
+
import { TOPOLOGY } from "../../../../../lib/topology.generated";
|
|
89
90
|
import {
|
|
90
91
|
magnetLandingMetadata,
|
|
91
92
|
magnetStartMetadata,
|
|
@@ -361,7 +362,15 @@ describe("the read tells a hub that is not configured from one that is down (#92
|
|
|
361
362
|
await expect(readMagnet("growth")).resolves.toEqual({ kind: "not-configured" });
|
|
362
363
|
});
|
|
363
364
|
|
|
364
|
-
|
|
365
|
+
// #9480 — the browser-facing name is read through the topology seam
|
|
366
|
+
// (#7874 D12). The committed seam is the hub render; #8060 — a spoke render
|
|
367
|
+
// reads no NEXT_PUBLIC_AILK_API_URL, so a spoke scaffold leaves that row out.
|
|
368
|
+
const CONFIGURED_BY =
|
|
369
|
+
TOPOLOGY === "hub"
|
|
370
|
+
? ORIGIN_NAMES
|
|
371
|
+
: ORIGIN_NAMES.filter((name) => name !== "NEXT_PUBLIC_AILK_API_URL");
|
|
372
|
+
|
|
373
|
+
it.each(CONFIGURED_BY)("with %s set, a 5xx or a throw is unavailable", async (name) => {
|
|
365
374
|
process.env[name] = "https://hub.example";
|
|
366
375
|
mockGet.mockResolvedValue({ ok: false, status: 503, body: null });
|
|
367
376
|
await expect(readMagnet("growth")).resolves.toEqual({ kind: "unavailable" });
|
|
@@ -378,6 +387,18 @@ describe("the read tells a hub that is not configured from one that is down (#92
|
|
|
378
387
|
await expect(readMagnet("growth")).resolves.toEqual({ kind: "not-configured" });
|
|
379
388
|
});
|
|
380
389
|
|
|
390
|
+
it("on a spoke (the seam's spoke render), NEXT_PUBLIC_AILK_API_URL alone is not-configured", async () => {
|
|
391
|
+
process.env.NEXT_PUBLIC_AILK_API_URL = "https://hub.example";
|
|
392
|
+
mockGet.mockResolvedValue({ ok: false, status: 503, body: null });
|
|
393
|
+
await jest.isolateModulesAsync(async () => {
|
|
394
|
+
jest.doMock("../../../../../lib/api-origin.generated", () => ({
|
|
395
|
+
browserApiOrigin: (): string | undefined => undefined,
|
|
396
|
+
}));
|
|
397
|
+
const spoke = await import("../magnet-page");
|
|
398
|
+
await expect(spoke.readMagnet("growth")).resolves.toEqual({ kind: "not-configured" });
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
|
|
381
402
|
it("with no API origin, a 404 is still absent and a served flow still ok", async () => {
|
|
382
403
|
mockGet.mockResolvedValue({ ok: false, status: 404, body: null });
|
|
383
404
|
await expect(readMagnet("growth")).resolves.toEqual({ kind: "absent" });
|
|
@@ -51,6 +51,7 @@ import { notFound, redirect } from "next/navigation";
|
|
|
51
51
|
import { getTranslations } from "next-intl/server";
|
|
52
52
|
import type { ReactElement } from "react";
|
|
53
53
|
|
|
54
|
+
import { browserApiOrigin } from "../../../../lib/api-origin.generated";
|
|
54
55
|
import { readSiteContactEmail } from "../../contact/site-contact-email";
|
|
55
56
|
|
|
56
57
|
import { FlowStepperClient } from "./FlowStepperClient";
|
|
@@ -74,13 +75,16 @@ const magnetReads = new Map<string, { at: number; read: Promise<MagnetRead> }>()
|
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
77
|
* Whether an API origin is configured: the three names `getApiBase()` in
|
|
77
|
-
* packages/api-client/src/http.ts reads, in step with it
|
|
78
|
-
*
|
|
78
|
+
* packages/api-client/src/http.ts reads, in step with it on a hub. Without one
|
|
79
|
+
* that function answers `localhost:3001`. The browser-facing origin comes from
|
|
80
|
+
* the topology seam (#7874 D12), which a spoke renders with no env read, so a
|
|
81
|
+
* spoke passes its own `env:check` (#9480). A spoke diverges on purpose: the
|
|
82
|
+
* browser-facing name set on one at runtime counts as no origin here.
|
|
79
83
|
*/
|
|
80
84
|
function apiOriginConfigured(): boolean {
|
|
81
85
|
return Boolean(
|
|
82
86
|
process.env.AILK_API_URL ||
|
|
83
|
-
|
|
87
|
+
browserApiOrigin() ||
|
|
84
88
|
process.env.NEXT_PUBLIC_API_URL,
|
|
85
89
|
);
|
|
86
90
|
}
|